taskRepository = $taskRepository; $this->userTaskRepository = $userTaskRepository; $this->userProgressRepository = $userProgressRepository; $this->resetLogRepository = $resetLogRepository; $this->conditionService = $conditionService; } /** * 更新任务进度 * * @param int $userId 用户ID * @param int $taskId 任务ID * @param int $progress 进度值(0-100) * @return array 更新结果 */ public function updateTaskProgress(int $userId, int $taskId, int $progress): array { try { // 获取用户任务 $userTask = $this->userTaskRepository->getUserTask($userId, $taskId); if (!$userTask) { throw new \Exception('未接取该任务'); } // 检查任务状态 if ($userTask->status !== TASK_STATUS::IN_PROGRESS->value) { throw new \Exception('只能更新进行中的任务进度'); } // 验证进度值 if ($progress < 0 || $progress > 100) { throw new \Exception('进度值必须在0-100之间'); } // 检查任务是否需要重置 $this->checkAndResetTask($userTask); // 更新任务进度 $userTask->progress = $progress; $userTask->save(); // 如果进度达到100%,检查是否可以完成任务 if ($progress === 100) { return $this->checkTaskCompletion($userId, $taskId); } return [ 'success' => true, 'message' => '任务进度更新成功', 'progress' => $progress, ]; } catch (\Exception $e) { Log::error('任务进度更新失败', [ 'user_id' => $userId, 'task_id' => $taskId, 'progress' => $progress, 'error' => $e->getMessage(), ]); return [ 'success' => false, 'message' => '任务进度更新失败: ' . $e->getMessage(), ]; } } /** * 检查任务完成状态 * * @param int $userId 用户ID * @param int $taskId 任务ID * @return array 检查结果 */ public function checkTaskCompletion(int $userId, int $taskId): array { try { // 开始事务 DB::beginTransaction(); // 获取用户任务 $userTask = $this->userTaskRepository->getUserTask($userId, $taskId); if (!$userTask) { throw new \Exception('未接取该任务'); } // 检查任务状态 if ($userTask->status !== TASK_STATUS::IN_PROGRESS->value) { throw new \Exception('只能完成进行中的任务'); } // 检查任务进度 if ($userTask->progress < 100) { throw new \Exception('任务进度未达到100%'); } // 获取任务信息 $task = $this->taskRepository->find($taskId); // 更新任务状态 $userTask->status = TASK_STATUS::COMPLETED->value; $userTask->completed_at = Carbon::now(); $userTask->save(); // 触发任务完成事件 event(new TaskCompletedEvent( $userId, $taskId, $task->name, $userTask->completed_at )); // 提交事务 DB::commit(); return [ 'success' => true, 'message' => '任务完成成功', 'user_task' => $userTask, ]; } catch (\Exception $e) { // 回滚事务 DB::rollBack(); Log::error('任务完成检查失败', [ 'user_id' => $userId, 'task_id' => $taskId, 'error' => $e->getMessage(), ]); return [ 'success' => false, 'message' => '任务完成检查失败: ' . $e->getMessage(), ]; } } /** * 检查并重置任务 * * @param TaskUserTask $userTask 用户任务 * @return bool 是否重置 */ public function checkAndResetTask(TaskUserTask $userTask): bool { try { // 获取任务信息 $task = $this->taskRepository->find($userTask->task_id); if (!$task) { return false; } // 如果任务不需要重置,直接返回 if (!$task->reset_type || $task->reset_type === 'none') { return false; } // 如果任务状态不是已完成或已领取奖励,不需要重置 if (!in_array($userTask->status, [TASK_STATUS::COMPLETED->value, TASK_STATUS::REWARDED->value])) { return false; } // 检查是否需要重置 $needReset = $this->needReset($userTask, $task); if ($needReset) { // 重置任务 return $this->resetTask($userTask, $task); } return false; } catch (\Exception $e) { Log::error('检查并重置任务失败', [ 'user_task_id' => $userTask->id, 'user_id' => $userTask->user_id, 'task_id' => $userTask->task_id, 'error' => $e->getMessage(), ]); return false; } } /** * 检查任务是否需要重置 * * @param TaskUserTask $userTask 用户任务 * @param Task $task 任务 * @return bool 是否需要重置 */ protected function needReset(TaskUserTask $userTask, Task $task): bool { // 获取当前时间 $now = Carbon::now(); // 如果下次重置时间未设置,则计算下次重置时间 if (!$userTask->next_reset_time) { // 如果上次重置时间未设置,则使用任务完成时间或当前时间 $lastResetTime = $userTask->last_reset_time ?? $userTask->completed_at ?? $now; // 计算下次重置时间 $nextResetTime = $this->calculateNextResetTime($task->reset_type, $lastResetTime); // 更新下次重置时间 $userTask->next_reset_time = $nextResetTime; $userTask->save(); // 如果下次重置时间已过,则需要重置 return $now->greaterThanOrEqualTo($nextResetTime); } // 如果当前时间已超过下次重置时间,则需要重置 return $now->greaterThanOrEqualTo($userTask->next_reset_time); } /** * 计算下次重置时间 * * @param string $resetType 重置类型 * @param Carbon $lastResetTime 上次重置时间 * @return Carbon 下次重置时间 */ protected function calculateNextResetTime(string $resetType, Carbon $lastResetTime): Carbon { $resetType = RESET_TYPE::tryFrom($resetType) ?? RESET_TYPE::NONE; // 获取重置间隔(秒) $interval = RESET_TYPE::getInterval($resetType); if ($interval === null) { // 如果没有重置间隔,则返回一个很远的未来时间 return Carbon::now()->addYears(100); } // 计算下次重置时间 return $lastResetTime->copy()->addSeconds($interval); } /** * 重置任务 * * @param TaskUserTask $userTask 用户任务 * @param Task $task 任务 * @return bool 是否成功 */ protected function resetTask(TaskUserTask $userTask, Task $task): bool { try { // 开始事务 DB::beginTransaction(); // 记录重置前的状态 $oldStatus = $userTask->status; $oldProgress = $userTask->progress; // 重置任务进度 $this->conditionService->resetTaskProgress($userTask->user_id, $userTask->task_id); // 更新任务状态 $userTask->status = TASK_STATUS::IN_PROGRESS->value; $userTask->progress = 0; $userTask->completed_at = null; $userTask->rewarded_at = null; $userTask->last_reset_time = Carbon::now(); // 计算下次重置时间 $userTask->next_reset_time = $this->calculateNextResetTime($task->reset_type, $userTask->last_reset_time); // 增加重置次数 $userTask->reset_count = ($userTask->reset_count ?? 0) + 1; // 保存更新 $userTask->save(); // 记录重置日志 $this->resetLogRepository->create([ 'user_id' => $userTask->user_id, 'task_id' => $userTask->task_id, 'user_task_id' => $userTask->id, 'reset_type' => $task->reset_type, 'old_status' => $oldStatus, 'old_progress' => $oldProgress, 'reset_time' => $userTask->last_reset_time, 'next_reset_time' => $userTask->next_reset_time, 'reset_count' => $userTask->reset_count, ]); // 提交事务 DB::commit(); return true; } catch (\Exception $e) { // 回滚事务 DB::rollBack(); Log::error('重置任务失败', [ 'user_task_id' => $userTask->id, 'user_id' => $userTask->user_id, 'task_id' => $userTask->task_id, 'error' => $e->getMessage(), ]); return false; } } /** * 批量检查并重置任务 * * @param int $userId 用户ID * @param string|null $resetType 重置类型(可选) * @return array 重置结果 */ public function batchCheckAndResetTasks(int $userId, ?string $resetType = null): array { try { // 获取用户任务 $query = $this->userTaskRepository->query() ->where('user_id', $userId) ->whereIn('status', [TASK_STATUS::COMPLETED->value, TASK_STATUS::REWARDED->value]); // 如果指定了重置类型,则筛选任务 if ($resetType) { $query->whereHas('task', function ($q) use ($resetType) { $q->where('reset_type', $resetType); }); } $userTasks = $query->get(); // 重置任务 $resetCount = 0; foreach ($userTasks as $userTask) { $task = $this->taskRepository->find($userTask->task_id); if (!$task) { continue; } if ($this->checkAndResetTask($userTask)) { $resetCount++; } } return [ 'success' => true, 'message' => "已重置{$resetCount}个任务", 'reset_count' => $resetCount, 'total_count' => $userTasks->count(), ]; } catch (\Exception $e) { Log::error('批量检查并重置任务失败', [ 'user_id' => $userId, 'reset_type' => $resetType, 'error' => $e->getMessage(), ]); return [ 'success' => false, 'message' => '批量检查并重置任务失败: ' . $e->getMessage(), ]; } } /** * 获取用户任务进度 * * @param int $userId 用户ID * @param int $taskId 任务ID * @return array 任务进度 */ public function getTaskProgress(int $userId, int $taskId): array { try { // 获取用户任务 $userTask = $this->userTaskRepository->getUserTask($userId, $taskId); if (!$userTask) { throw new \Exception('未接取该任务'); } // 获取任务条件进度 $conditionProgress = $this->userProgressRepository->getUserTaskProgress($userId, $taskId); return [ 'success' => true, 'task_id' => $taskId, 'user_id' => $userId, 'status' => $userTask->status, 'progress' => $userTask->progress, 'completed_at' => $userTask->completed_at, 'rewarded_at' => $userTask->rewarded_at, 'condition_progress' => $conditionProgress, ]; } catch (\Exception $e) { Log::error('获取任务进度失败', [ 'user_id' => $userId, 'task_id' => $taskId, 'error' => $e->getMessage(), ]); return [ 'success' => false, 'message' => '获取任务进度失败: ' . $e->getMessage(), ]; } } }