info('开始清理划转订单数据...'); try { // 获取命令参数 $days = (int) $this->option('days'); $status = $this->option('status'); $limit = (int) $this->option('limit'); $dryRun = $this->option('dry-run'); $force = $this->option('force'); if ($days <= 0) { $this->error('天数必须大于0'); return 1; } // 计算截止日期 $cutoffDate = Carbon::now()->subDays($days); $this->info("将清理 {$cutoffDate->format('Y-m-d H:i:s')} 之前的数据"); // 构建查询 $query = TransferOrder::where('created_at', '<', $cutoffDate); if ($status) { $statusEnum = TransferStatus::tryFrom((int) $status); if (!$statusEnum) { $this->error("无效的状态值: {$status}"); $this->showStatusOptions(); return 1; } $query->where('status', $statusEnum); $this->info("只清理状态为 {$statusEnum->getDescription()} 的订单"); } else { // 默认只清理已完成或失败的订单 $query->whereIn('status', [TransferStatus::COMPLETED, TransferStatus::FAILED]); $this->info('只清理已完成或失败的订单'); } // 获取统计信息 $totalCount = $query->count(); if ($totalCount === 0) { $this->info('没有找到需要清理的数据'); return 0; } $this->info("找到 {$totalCount} 条记录需要清理"); // 显示详细统计 $this->showStatistics($cutoffDate, $status); if ($dryRun) { $this->info('这是预览模式,不会实际删除数据'); return 0; } // 确认操作 if (!$force) { if (!$this->confirm("确定要删除这 {$totalCount} 条记录吗?此操作不可恢复!")) { $this->info('操作已取消'); return 0; } } // 分批删除 $deletedCount = 0; $batchCount = 0; while (true) { $batch = $query->limit($limit)->get(); if ($batch->isEmpty()) { break; } $batchCount++; $this->info("处理第 {$batchCount} 批,共 {$batch->count()} 条记录..."); DB::transaction(function () use ($batch, &$deletedCount) { foreach ($batch as $order) { // 记录删除日志 Log::info('Transfer order cleaned', [ 'order_id' => $order->id, 'type' => $order->type->value, 'status' => $order->status->value, 'amount' => $order->amount, 'created_at' => $order->created_at->toISOString() ]); $order->delete(); $deletedCount++; } }); $this->line("已删除 {$deletedCount} / {$totalCount} 条记录"); // 避免内存泄漏 unset($batch); // 短暂休息 usleep(100000); // 0.1秒 } $this->info("清理完成!共删除 {$deletedCount} 条记录"); // 记录清理操作 Log::info('Transfer clean command completed', [ 'deleted_count' => $deletedCount, 'cutoff_date' => $cutoffDate->toISOString(), 'status_filter' => $status, 'days' => $days ]); return 0; } catch (\Exception $e) { $this->error("清理失败: {$e->getMessage()}"); Log::error('Transfer clean command failed', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return 1; } } /** * 显示统计信息 * * @param Carbon $cutoffDate * @param string|null $status * @return void */ protected function showStatistics(Carbon $cutoffDate, ?string $status): void { $this->info('数据统计:'); $baseQuery = TransferOrder::where('created_at', '<', $cutoffDate); if ($status) { $statusEnum = TransferStatus::tryFrom((int) $status); $baseQuery->where('status', $statusEnum); } else { $baseQuery->whereIn('status', [TransferStatus::COMPLETED, TransferStatus::FAILED]); } // 按状态统计 $statusStats = []; foreach (TransferStatus::cases() as $statusCase) { $count = (clone $baseQuery)->where('status', $statusCase)->count(); if ($count > 0) { $statusStats[] = " {$statusCase->getDescription()}: {$count} 条"; } } if (!empty($statusStats)) { $this->line(implode("\n", $statusStats)); } // 按类型统计 $typeStats = (clone $baseQuery) ->select('type', DB::raw('count(*) as count')) ->groupBy('type') ->get(); if ($typeStats->isNotEmpty()) { $this->line('按类型统计:'); foreach ($typeStats as $stat) { $typeEnum = \App\Module\Transfer\Enums\TransferType::from($stat->type); $this->line(" {$typeEnum->getDescription()}: {$stat->count} 条"); } } } /** * 显示状态选项 * * @return void */ protected function showStatusOptions(): void { $this->info('可用的状态值:'); foreach (TransferStatus::cases() as $status) { $this->line(" {$status->value} - {$status->getDescription()}"); } } }