expireUser(); // 过期用户处理 $this->closeTickets(); // 关闭用户超时未处理的工单 if (sysConfig('reset_traffic')) { $this->resetUserTraffic(); // 重置用户流量 } if (sysConfig('auto_release_port')) { $this->releaseAccountPort(); // 账号端口回收 } $this->userTrafficStatistics(); // 用户每日流量统计 $this->nodeTrafficStatistics(); // 节点每日流量统计 $jobTime = round(microtime(true) - $jobTime, 4); Log::info(__('----「:job」Completed, Used :time seconds ----', ['job' => $this->description, 'time' => $jobTime])); } private function expireUser(): void { // 过期用户处理 $isBanStatus = sysConfig('is_ban_status'); $dirtyWorks = [ 'u' => 0, 'd' => 0, 'transfer_enable' => 0, 'enable' => 0, 'level' => 0, 'reset_time' => null, 'ban_time' => null, ]; // 清理账号 & 停止服务 $banMsg = __('[Daily Task] Account Expiration: Stop Service'); if ($isBanStatus) { $dirtyWorks['status'] = -1; // 封禁账号 $banMsg = __('[Daily Task] Account Expiration: Block Login & Clear Account'); } User::activeUser()->where('expired_at', '<', date('Y-m-d')) // 过期 ->chunk(sysConfig('tasks_chunk'), function ($users) use ($banMsg, $dirtyWorks) { $users->each(function ($user) use ($banMsg, $dirtyWorks) { $user->update($dirtyWorks); Helpers::addUserTrafficModifyLog($user->id, $user->transfer_enable, 0, $banMsg); $user->banedLogs()->create(['description' => $banMsg]); }); }); } private function closeTickets(): void { // 关闭用户超时未处理的工单 $closeTicketsHours = (time() - strtotime(sysConfig('tasks_close.tickets'))) / 3600; Ticket::whereStatus(1)->with('reply')->whereHas('reply', function ($query) { $query->where('admin_id', '<>', null); })->where('updated_at', '<=', date('Y-m-d H:i:s', strtotime(sysConfig('tasks_close.tickets'))))->chunk(sysConfig('tasks_chunk'), function ($tickets) use ($closeTicketsHours) { $tickets->each(function ($ticket) use ($closeTicketsHours) { if ($ticket->close()) { $ticket->user->notify(new TicketClosed($ticket->id, $ticket->title, route('ticket.edit', $ticket), __('You have not responded this ticket in :num hours, System has closed your ticket.', ['num' => $closeTicketsHours]), true)); } }); }); } private function resetUserTraffic(): void { // 重置用户流量 $today = date('Y-m-d'); User::where('status', '<>', -1)->where('expired_at', '>', $today)->where('reset_time', '<=', $today)->whereHas('orders', function ($query) { $query->activePlan(); })->with(['orders' => function ($query) { $query->activePlan(); }])->chunk(sysConfig('tasks_chunk'), function ($users) { $users->each(function ($user) { $user->orders()->activePackage()->update(['is_expire' => 1]); // 过期生效中的加油包 $order = $user->orders->first(); // 取出用户正在使用的套餐 $oldData = $user->transfer_enable; // 重置流量与重置日期 if ($user->update((new OrderService($order))->resetTimeAndData($user->expired_at))) { Helpers::addUserTrafficModifyLog($order->user_id, $oldData, $user->transfer_enable, trans('[Daily Task] Reset Account Traffic, Next Reset Date: :date', ['date' => $user->reset_date]), $order->id); } else { Log::error(trans('notification.reset_failed', ['uid' => $user->id, 'username' => $user->username])); } }); }); } private function releaseAccountPort(): void { // 被封禁 / 过期N天 的账号自动释放端口 User::where('port', '<>', 0)->where(function (Builder $query) { $query->whereStatus(-1)->orWhere('expired_at', '<=', date('Y-m-d', strtotime('-'.sysConfig('auto_release_port').' days'))); })->update(['port' => 0]); } private function userTrafficStatistics(): void { $created_at = date('Y-m-d 23:59:59', strtotime('yesterday')); $end = strtotime($created_at); $start = $end - 86399; User::activeUser()->whereHas('dataFlowLogs', function (Builder $query) use ($start, $end) { $query->whereBetween('log_time', [$start, $end]); })->with([ 'dataFlowLogs' => function ($query) use ($start, $end) { $query->whereBetween('log_time', [$start, $end]); }, ])->chunk(sysConfig('tasks_chunk'), function ($users) use ($created_at) { foreach ($users as $user) { $dataFlowLogs = $user->dataFlowLogs->groupBy('node_id'); $data = $dataFlowLogs->map(function ($logs, $nodeId) use ($created_at) { $totals = $logs->reduce(function ($carry, $log) { $carry['u'] += $log['u']; $carry['d'] += $log['d']; return $carry; }, ['u' => 0, 'd' => 0]); return [ 'node_id' => $nodeId, 'u' => $totals['u'], 'd' => $totals['d'], 'created_at' => $created_at, ]; })->values()->all(); $data[] = [ // 每日节点流量合计 'node_id' => null, 'u' => array_sum(array_column($data, 'u')), 'd' => array_sum(array_column($data, 'd')), 'created_at' => $created_at, ]; $user->dailyDataFlows()->createMany($data); } }); } private function nodeTrafficStatistics(): void { $created_at = date('Y-m-d 23:59:59', strtotime('yesterday')); $end = strtotime($created_at); $start = $end - 86399; Node::whereHas('userDataFlowLogs', function (Builder $query) use ($start, $end) { $query->whereBetween('log_time', [$start, $end]); })->withCount([ 'userDataFlowLogs as u_sum' => function ($query) use ($start, $end) { $query->select(DB::raw('SUM(u)'))->whereBetween('log_time', [$start, $end]); }, ])->withCount([ 'userDataFlowLogs as d_sum' => function ($query) use ($start, $end) { $query->select(DB::raw('SUM(d)'))->whereBetween('log_time', [$start, $end]); }, ])->chunk(sysConfig('tasks_chunk'), function ($nodes) use ($created_at) { foreach ($nodes as $node) { $node->dailyDataFlows()->create([ 'u' => $node->u_sum, 'd' => $node->d_sum, 'created_at' => $created_at, ]); } }); $dailyTotal = NodeDailyDataFlow::whereNotNull('node_id')->whereCreatedAt($created_at)->selectRaw('SUM(u) as total_u, SUM(d) as total_d')->first(); if ($dailyTotal) { NodeDailyDataFlow::create([ 'u' => $dailyTotal->total_u, 'd' => $dailyTotal->total_d, 'created_at' => $created_at, ]); } } }