CleanExpiredActivitiesCommand.php 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. <?php
  2. namespace App\Module\Activity\Commands;
  3. use App\Module\Activity\Enums\ACTIVITY_STATUS;
  4. use App\Module\Activity\Enums\REWARD_STATUS;
  5. use App\Module\Activity\Models\ActivityConfig;
  6. use App\Module\Activity\Models\ActivityParticipation;
  7. use Carbon\Carbon;
  8. use Illuminate\Console\Command;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Log;
  11. use UCore\Helper\Logger;
  12. /**
  13. * 清理过期活动命令
  14. */
  15. class CleanExpiredActivitiesCommand extends Command
  16. {
  17. /**
  18. * 命令名称
  19. *
  20. * @var string
  21. */
  22. protected $signature = 'activity:clean-expired {--days=30 : 清理多少天前结束的活动} {--dry-run : 仅显示将要清理的内容,不实际执行}';
  23. /**
  24. * 命令描述
  25. *
  26. * @var string
  27. */
  28. protected $description = '清理过期活动和未领取的奖励';
  29. /**
  30. * 执行命令
  31. *
  32. * @return int
  33. */
  34. public function handle()
  35. {
  36. $days = (int)$this->option('days');
  37. $dryRun = $this->option('dry-run');
  38. if ($days <= 0) {
  39. $this->error('天数必须大于0');
  40. return 1;
  41. }
  42. $cutoffDate = Carbon::now()->subDays($days);
  43. $this->info("开始清理 {$cutoffDate} 之前结束的活动...");
  44. if ($dryRun) {
  45. $this->warn('当前为演示模式,不会实际执行清理操作');
  46. }
  47. // 查找过期活动
  48. $expiredActivities = ActivityConfig::where('end_time', '<', $cutoffDate)
  49. ->whereIn('status', [ACTIVITY_STATUS::ENDED, ACTIVITY_STATUS::CLOSED])
  50. ->get();
  51. $this->info("找到 " . count($expiredActivities) . " 个过期活动");
  52. if ($expiredActivities->isEmpty()) {
  53. $this->info('没有需要清理的过期活动');
  54. return 0;
  55. }
  56. // 显示将要清理的活动
  57. $this->table(
  58. ['ID', '名称', '结束时间', '状态'],
  59. $expiredActivities->map(function ($activity) {
  60. return [
  61. $activity->id,
  62. $activity->name,
  63. $activity->end_time,
  64. ACTIVITY_STATUS::getName($activity->status)
  65. ];
  66. })
  67. );
  68. if (!$dryRun && !$this->confirm('确定要清理这些活动吗?此操作不可撤销')) {
  69. $this->info('操作已取消');
  70. return 0;
  71. }
  72. // 清理过期活动
  73. $expiredActivityIds = $expiredActivities->pluck('id')->toArray();
  74. $expiredRewardsCount = 0;
  75. if (!$dryRun) {
  76. DB::beginTransaction();
  77. try {
  78. // 标记未领取的奖励为已过期
  79. $expiredRewardsCount = ActivityParticipation::whereIn('activity_id', $expiredActivityIds)
  80. ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
  81. ->update(['reward_status' => REWARD_STATUS::EXPIRED]);
  82. // 更新活动状态为已关闭
  83. ActivityConfig::whereIn('id', $expiredActivityIds)
  84. ->where('status', ACTIVITY_STATUS::ENDED)
  85. ->update(['status' => ACTIVITY_STATUS::CLOSED]);
  86. DB::commit();
  87. $this->info("成功清理 " . count($expiredActivityIds) . " 个过期活动");
  88. $this->info("标记 {$expiredRewardsCount} 个未领取的奖励为已过期");
  89. // 记录日志
  90. Log::info("清理过期活动完成", [
  91. 'activity_count' => count($expiredActivityIds),
  92. 'expired_rewards_count' => $expiredRewardsCount,
  93. 'cutoff_date' => $cutoffDate
  94. ]);
  95. } catch (\Exception $e) {
  96. DB::rollBack();
  97. $this->error("清理过期活动失败: " . $e->getMessage());
  98. // 记录日志
  99. Logger::error("清理过期活动失败", [
  100. 'error' => $e->getMessage(),
  101. 'cutoff_date' => $cutoffDate
  102. ]);
  103. return 1;
  104. }
  105. } else {
  106. // 演示模式,显示将要执行的操作
  107. $expiredRewardsCount = ActivityParticipation::whereIn('activity_id', $expiredActivityIds)
  108. ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
  109. ->count();
  110. $this->info("将会清理 " . count($expiredActivityIds) . " 个过期活动");
  111. $this->info("将会标记 {$expiredRewardsCount} 个未领取的奖励为已过期");
  112. }
  113. return 0;
  114. }
  115. }