option('fix-null'); $this->info('🚀 开始执行流量重置任务...'); if ($fixNull) { $this->warn('🔧 修正模式 - 将重新计算next_reset_at为null的用户'); } try { $result = $fixNull ? $this->performFix() : $this->performReset(); $this->displayResults($result, $fixNull); return self::SUCCESS; } catch (\Exception $e) { $this->error("❌ 任务执行失败: {$e->getMessage()}"); Log::error('流量重置命令执行失败', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), ]); return self::FAILURE; } } private function displayResults(array $result, bool $fixNull): void { $this->info("✅ 任务完成!\n"); if ($fixNull) { $this->displayFixResults($result); } else { $this->displayExecutionResults($result); } } private function displayFixResults(array $result): void { $this->info("📊 修正结果统计:"); $this->info("🔍 发现用户总数: {$result['total_found']}"); $this->info("✅ 成功修正数量: {$result['total_fixed']}"); $this->info("⏱️ 总执行时间: {$result['duration']} 秒"); if ($result['error_count'] > 0) { $this->warn("⚠️ 错误数量: {$result['error_count']}"); $this->warn("详细错误信息请查看日志"); } else { $this->info("✨ 无错误发生"); } if ($result['total_found'] > 0) { $avgTime = round($result['duration'] / $result['total_found'], 4); $this->info("⚡ 平均处理速度: {$avgTime} 秒/用户"); } } private function displayExecutionResults(array $result): void { $this->info("📊 执行结果统计:"); $this->info("👥 处理用户总数: {$result['total_processed']}"); $this->info("🔄 重置用户数量: {$result['total_reset']}"); $this->info("⏱️ 总执行时间: {$result['duration']} 秒"); if ($result['error_count'] > 0) { $this->warn("⚠️ 错误数量: {$result['error_count']}"); $this->warn("详细错误信息请查看日志"); } else { $this->info("✨ 无错误发生"); } if ($result['total_processed'] > 0) { $avgTime = round($result['duration'] / $result['total_processed'], 4); $this->info("⚡ 平均处理速度: {$avgTime} 秒/用户"); } } private function performReset(): array { $startTime = microtime(true); $totalResetCount = 0; $errors = []; $users = $this->getResetQuery()->get(); if ($users->isEmpty()) { $this->info("😴 当前没有需要重置的用户"); return [ 'total_processed' => 0, 'total_reset' => 0, 'error_count' => 0, 'duration' => round(microtime(true) - $startTime, 2), ]; } $this->info("找到 {$users->count()} 个需要重置的用户"); foreach ($users as $user) { try { $totalResetCount += (int) $this->trafficResetService->checkAndReset($user, TrafficResetLog::SOURCE_CRON); } catch (\Exception $e) { $errors[] = [ 'user_id' => $user->id, 'email' => $user->email, 'error' => $e->getMessage(), ]; Log::error('用户流量重置失败', [ 'user_id' => $user->id, 'error' => $e->getMessage(), ]); } } return [ 'total_processed' => $users->count(), 'total_reset' => $totalResetCount, 'error_count' => count($errors), 'duration' => round(microtime(true) - $startTime, 2), ]; } private function performFix(): array { $startTime = microtime(true); $nullUsers = $this->getNullResetTimeUsers(); if ($nullUsers->isEmpty()) { $this->info("✅ 没有发现next_reset_at为null的用户"); return [ 'total_found' => 0, 'total_fixed' => 0, 'error_count' => 0, 'duration' => round(microtime(true) - $startTime, 2), ]; } $this->info("🔧 发现 {$nullUsers->count()} 个next_reset_at为null的用户,开始修正..."); $fixedCount = 0; $errors = []; foreach ($nullUsers as $user) { try { $nextResetTime = $this->trafficResetService->calculateNextResetTime($user); if ($nextResetTime) { $user->next_reset_at = $nextResetTime->timestamp; $user->save(); $fixedCount++; } } catch (\Exception $e) { $errors[] = [ 'user_id' => $user->id, 'email' => $user->email, 'error' => $e->getMessage(), ]; Log::error('修正用户next_reset_at失败', [ 'user_id' => $user->id, 'error' => $e->getMessage(), ]); } } return [ 'total_found' => $nullUsers->count(), 'total_fixed' => $fixedCount, 'error_count' => count($errors), 'duration' => round(microtime(true) - $startTime, 2), ]; } private function getResetQuery() { return User::where('next_reset_at', '<=', time()) ->whereNotNull('next_reset_at') ->where(function ($query) { $query->where('expired_at', '>', time()) ->orWhereNull('expired_at'); }) ->where('banned', 0) ->whereNotNull('plan_id'); } private function getNullResetTimeUsers() { return User::whereNull('next_reset_at') ->whereNotNull('plan_id') ->where(function ($query) { $query->where('expired_at', '>', time()) ->orWhereNull('expired_at'); }) ->where('banned', 0) ->with('plan:id,name,reset_traffic_method') ->get(); } }