123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- <?php
- namespace app\common\command;
- use app\common\model\FlowLogs;
- use app\common\model\User;
- use app\common\model\UserTraffic;
- use think\console\Command;
- use think\console\Input;
- use think\console\Output;
- use think\Db;
- use think\Exception;
- class SettlementTraffic extends Command
- {
- protected function configure()
- {
- // parent::configure(); // TODO: Change the autogenerated stub
- $this->setName('settlement')->setDescription('后台统计用户流量使用, 并扣除相关流量');
- }
- /**
- * 功能: 执行任务, 计算统计使用的流量
- * @param Input $input
- * @param Output $output
- * @return int|void|null
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\ModelNotFoundException
- * @throws \think\exception\DbException
- */
- protected function execute(Input $input, Output $output)
- {
- // parent::execute($input, $output); // TODO: Change the autogenerated stub
- // $output->writeln("TestCommand");
- $dateTime = time() - 5; // 设置处理数据的时间为当前时间的前5秒,避免数据竞争
- // 分组统计出指定时间内用户使用了的流量
- $data = FlowLogs::where('created_at', '<=', $dateTime)
- ->field('username, sum(bytes) as bytes')
- ->group('username')
- ->select()->toArray();
- // 当前数据所有用户名的数组
- $userNames = array_column($data, 'username');
- $users = collection(User::whereIn('username', $userNames)->field('id, username')->select())->toArray();
- $userNameMapId = array_column($users, 'id', 'username');
- Db::startTrans();
- try {
- foreach ($data as $datum) {
- if (!$this->usedTraffic($userNameMapId[$datum['username']], $datum['bytes'], $dateTime)) {
- throw new Exception('统计用户使用流量失败');
- }
- }
- // 指定时间段的流量已统计,删除相关记录
- FlowLogs::where('created_at', '<=', $dateTime)->delete();
- // 统计数据成功,提交事物
- Db::commit();
- } catch (Exception $e) { // 操作失败,数据库信息回滚
- Db::rollback();
- }
- }
- /**
- * 功能: 处理用户使用过的流量
- * @param $uid
- * @param $bytes
- * @param $dateTime
- * @return bool
- * @throws \think\db\exception\DataNotFoundException
- * @throws \think\db\exception\ModelNotFoundException
- * @throws \think\exception\DbException
- */
- protected function usedTraffic($uid, $bytes, $dateTime)
- {
- $usable = UserTraffic::where('uid', $uid)
- ->where('is_usable', '1')
- ->where('start_time', '<', $dateTime)
- ->where('expired_time', '>', $dateTime)
- ->order('expired_time', 'ASC')
- ->select();
- if (empty($usable)) {
- return true;
- }
- foreach ($usable as $item) {
- if ($bytes == 0) break;
- if ($item->traffic > bcadd($item->used, $bytes)) {
- $item->setInc('used', $bytes);
- } else {
- $bytes = bcsub($bytes, bcsub($item->traffic, $item->used));
- $item->used = $item->traffic;
- $item->is_usable = 0;
- $item->save();
- }
- }
- return true;
- }
- }
|