| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- <?php
- namespace App\Module\Transfer\Commands;
- use App\Module\Transfer\Models\TransferOrder;
- use App\Module\Transfer\Enums\TransferStatus;
- use Illuminate\Console\Command;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- use Carbon\Carbon;
- /**
- * 划转数据清理命令
- */
- class TransferCleanCommand extends Command
- {
- /**
- * 命令签名
- *
- * @var string
- */
- protected $signature = 'transfer:clean
- {--days=30 : 清理多少天前的数据}
- {--status= : 指定要清理的状态}
- {--limit=1000 : 每次处理的数量限制}
- {--dry-run : 仅显示将要清理的数据,不实际删除}
- {--force : 强制清理,跳过确认}';
- /**
- * 命令描述
- *
- * @var string
- */
- protected $description = '清理过期的划转订单数据';
- /**
- * 执行命令
- *
- * @return int
- */
- public function handle(): int
- {
- $this->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()}");
- }
- }
- }
|