TaskResetCheckCommand.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. <?php
  2. namespace App\Module\Task\Commands;
  3. use App\Module\Task\Enums\RESET_TYPE;
  4. use App\Module\Task\Enums\TASK_STATUS;
  5. use App\Module\Task\Models\Task;
  6. use App\Module\Task\Models\TaskUserTask;
  7. use Illuminate\Console\Command;
  8. use Illuminate\Support\Carbon;
  9. /**
  10. * 任务重置检查命令
  11. *
  12. * 用于诊断任务重置系统,检查哪些任务需要重置,以及重置状态是否正确。
  13. * 在被动重置机制下,此命令主要用于诊断和调试。
  14. */
  15. class TaskResetCheckCommand extends Command
  16. {
  17. /**
  18. * 命令名称
  19. *
  20. * @var string
  21. */
  22. protected $signature = 'task:reset-check
  23. {--user-id= : 指定用户ID进行检查}
  24. {--task-id= : 指定任务ID进行检查}
  25. {--reset-type= : 指定重置类型(daily, weekly, monthly, seasonal)}
  26. {--show-all : 显示所有任务,包括不需要重置的任务}
  27. {--detailed : 显示详细信息}';
  28. /**
  29. * 命令描述
  30. *
  31. * @var string
  32. */
  33. protected $description = '检查任务重置状态(用于诊断)';
  34. /**
  35. * 执行命令
  36. *
  37. * @return int
  38. */
  39. public function handle()
  40. {
  41. $this->info('开始检查任务重置状态...');
  42. // 获取命令选项
  43. $userId = $this->option('user-id');
  44. $taskId = $this->option('task-id');
  45. $resetType = $this->option('reset-type');
  46. $showAll = $this->option('show-all');
  47. $detailed = $this->option('detailed');
  48. // 验证重置类型
  49. if ($resetType && !in_array($resetType, ['daily', 'weekly', 'monthly', 'seasonal', 'none'])) {
  50. $this->error('无效的重置类型。有效值: daily, weekly, monthly, seasonal, none');
  51. return 1;
  52. }
  53. // 构建查询
  54. $query = TaskUserTask::query();
  55. // 应用过滤条件
  56. if ($userId) {
  57. $query->where('user_id', $userId);
  58. }
  59. if ($taskId) {
  60. $query->where('task_id', $taskId);
  61. }
  62. // 获取用户任务
  63. $userTasks = $query->with('task')->get();
  64. if ($userTasks->isEmpty()) {
  65. $this->warn('未找到符合条件的用户任务记录');
  66. return 0;
  67. }
  68. $this->info("找到 {$userTasks->count()} 条用户任务记录");
  69. // 创建表格头
  70. $headers = ['用户ID', '任务ID', '任务名称', '重置类型', '下次重置时间', '状态', '需要重置'];
  71. if ($detailed) {
  72. $headers = array_merge($headers, ['上次重置时间', '重置次数', '完成时间', '奖励领取时间']);
  73. }
  74. $rows = [];
  75. $needResetCount = 0;
  76. $now = Carbon::now();
  77. foreach ($userTasks as $userTask) {
  78. // 获取任务
  79. $task = $userTask->task;
  80. if (!$task) {
  81. continue;
  82. }
  83. // 获取重置类型
  84. $taskResetType = $task->reset_type ?? 'none';
  85. // 如果指定了重置类型,且不匹配,则跳过
  86. if ($resetType && $resetType !== $taskResetType) {
  87. continue;
  88. }
  89. // 检查是否需要重置
  90. $needReset = $this->checkNeedReset($userTask, $task, $now);
  91. // 如果不显示所有任务,且不需要重置,则跳过
  92. if (!$showAll && !$needReset) {
  93. continue;
  94. }
  95. if ($needReset) {
  96. $needResetCount++;
  97. }
  98. // 准备行数据
  99. $row = [
  100. $userTask->user_id,
  101. $userTask->task_id,
  102. $task->name ?? "未知任务({$userTask->task_id})",
  103. $taskResetType,
  104. $userTask->next_reset_time ? $userTask->next_reset_time->format('Y-m-d H:i:s') : '未设置',
  105. TASK_STATUS::getDescription(TASK_STATUS::from($userTask->status)),
  106. $needReset ? '是' : '否'
  107. ];
  108. if ($detailed) {
  109. $row = array_merge($row, [
  110. $userTask->last_reset_time ? $userTask->last_reset_time->format('Y-m-d H:i:s') : '未重置',
  111. $userTask->reset_count ?? 0,
  112. $userTask->completed_at ? $userTask->completed_at->format('Y-m-d H:i:s') : '未完成',
  113. $userTask->rewarded_at ? $userTask->rewarded_at->format('Y-m-d H:i:s') : '未领取'
  114. ]);
  115. }
  116. $rows[] = $row;
  117. }
  118. // 显示表格
  119. $this->table($headers, $rows);
  120. // 显示统计信息
  121. $this->info("需要重置的任务数量: {$needResetCount}");
  122. // 显示当前时间
  123. $this->info("当前系统时间: {$now->format('Y-m-d H:i:s')}");
  124. return 0;
  125. }
  126. /**
  127. * 检查任务是否需要重置
  128. *
  129. * @param TaskUserTask $userTask 用户任务
  130. * @param Task $task 任务
  131. * @param Carbon $now 当前时间
  132. * @return bool
  133. */
  134. protected function checkNeedReset(TaskUserTask $userTask, Task $task, Carbon $now): bool
  135. {
  136. // 如果任务不需要重置,则返回false
  137. if (!$task->reset_type || $task->reset_type === 'none') {
  138. return false;
  139. }
  140. // 如果任务状态不是已完成或已领取奖励,则不需要重置
  141. if (!in_array($userTask->status, [TASK_STATUS::COMPLETED->value, TASK_STATUS::REWARDED->value])) {
  142. return false;
  143. }
  144. // 如果下次重置时间未设置,则计算下次重置时间
  145. if (!$userTask->next_reset_time) {
  146. // 如果上次重置时间未设置,则使用当前时间
  147. $lastResetTime = $userTask->last_reset_time ?? $now;
  148. // 计算下次重置时间
  149. $nextResetTime = $this->calculateNextResetTime($task->reset_type, $lastResetTime);
  150. // 如果下次重置时间已过,则需要重置
  151. return $now->greaterThanOrEqualTo($nextResetTime);
  152. }
  153. // 如果当前时间已超过下次重置时间,则需要重置
  154. return $now->greaterThanOrEqualTo($userTask->next_reset_time);
  155. }
  156. /**
  157. * 计算下次重置时间
  158. *
  159. * @param string $resetType 重置类型
  160. * @param Carbon $lastResetTime 上次重置时间
  161. * @return Carbon
  162. */
  163. protected function calculateNextResetTime(string $resetType, Carbon $lastResetTime): Carbon
  164. {
  165. $resetType = RESET_TYPE::tryFrom($resetType) ?? RESET_TYPE::NONE;
  166. // 获取重置间隔(秒)
  167. $interval = RESET_TYPE::getInterval($resetType);
  168. if ($interval === null) {
  169. // 如果没有重置间隔,则返回一个很远的未来时间
  170. return Carbon::now()->addYears(100);
  171. }
  172. // 计算下次重置时间
  173. return $lastResetTime->copy()->addSeconds($interval);
  174. }
  175. }