'skipped', 'reason' => 'locked']; } // 创建锁文件 file_put_contents($lockFile, time()); try { Log::write('课程状态自动化任务开始' . date('Y-m-d H:i:s')); $result = $this->handleCourseStatus(); Log::write('课程状态自动化任务完成' . date('Y-m-d H:i:s')); return $result; } finally { // 删除锁文件 if (file_exists($lockFile)) { unlink($lockFile); } } } private function handleCourseStatus() { try { Db::startTrans(); $currentDate = date('Y-m-d'); $currentTime = date('H:i:s'); $currentDateTime = date('Y-m-d H:i:s'); // 先处理time_slot,解析并更新start_time和end_time字段 $this->updateTimeFields(); $completedCount = 0; $upcomingCount = 0; $ongoingCount = 0; $pendingCount = 0; // 1. 更新已完成课程:course_date < 当天的课程 $completedRows = CourseSchedule::where('course_date', '<', $currentDate) ->where('status', '<>', 'completed') ->update([ 'status' => 'completed', 'updated_at' => time() ]); $completedCount = $completedRows; // 2. 处理今天的课程,需要根据时间段判断状态 $todaySchedules = CourseSchedule::where('course_date', '=', $currentDate) ->whereIn('status', ['pending', 'upcoming', 'ongoing']) ->select(); foreach ($todaySchedules as $schedule) { $startTime = $schedule['start_time']; $endTime = $schedule['end_time']; if (empty($startTime) || empty($endTime)) { // 如果没有解析出时间,尝试从time_slot解析 $timeData = $this->parseTimeSlot($schedule['time_slot']); if ($timeData) { $startTime = $timeData['start_time']; $endTime = $timeData['end_time']; // 更新数据库中的时间字段 CourseSchedule::where('id', $schedule['id'])->update([ 'start_time' => $startTime, 'end_time' => $endTime ]); } else { continue; // 无法解析时间,跳过 } } // 判断课程状态 $newStatus = $this->determineStatus($currentTime, $startTime, $endTime); if ($newStatus !== $schedule['status']) { CourseSchedule::where('id', $schedule['id'])->update([ 'status' => $newStatus, 'updated_at' => time() ]); switch ($newStatus) { case 'upcoming': $upcomingCount++; break; case 'ongoing': $ongoingCount++; break; case 'completed': $completedCount++; break; default: $pendingCount++; break; } } } // 3. 重置未来日期的课程为pending状态 $futureRows = CourseSchedule::where('course_date', '>', $currentDate) ->where('status', '<>', 'pending') ->update([ 'status' => 'pending', 'updated_at' => time() ]); $pendingCount += $futureRows; Log::write("课程状态更新完成 - 已完成: {$completedCount}个, 即将开始: {$upcomingCount}个, 进行中: {$ongoingCount}个, 待安排: {$pendingCount}个"); Db::commit(); return [ 'status' => 'success', 'completed_count' => $completedCount, 'upcoming_count' => $upcomingCount, 'ongoing_count' => $ongoingCount, 'pending_count' => $pendingCount ]; } catch (\Exception $e) { Db::rollback(); Log::write('更新课程状态失败:' . $e->getMessage()); return [ 'status' => 'failed', 'total_count' => 0, 'updated_count' => 0, 'error' => $e->getMessage() ]; } } /** * 更新课程安排表的start_time和end_time字段 */ private function updateTimeFields() { try { // 查询所有没有start_time或end_time的记录 $schedules = CourseSchedule::where(function($query) { $query->whereNull('start_time') ->whereOr('end_time', null) ->whereOr('start_time', '') ->whereOr('end_time', ''); })->select(); foreach ($schedules as $schedule) { $timeData = $this->parseTimeSlot($schedule['time_slot']); if ($timeData) { CourseSchedule::where('id', $schedule['id'])->update([ 'start_time' => $timeData['start_time'], 'end_time' => $timeData['end_time'] ]); } } } catch (\Exception $e) { Log::write('更新时间字段失败:' . $e->getMessage()); } } /** * 解析time_slot字符串,提取开始和结束时间 * @param string $timeSlot 格式如 "09:00-10:30" * @return array|null */ private function parseTimeSlot($timeSlot) { if (empty($timeSlot)) { return null; } // 支持多种格式:09:00-10:30, 09:00~10:30, 9:00-10:30 if (preg_match('/(\d{1,2}:\d{2})\s*[-~~]\s*(\d{1,2}:\d{2})/', $timeSlot, $matches)) { return [ 'start_time' => $matches[1], 'end_time' => $matches[2] ]; } return null; } /** * 根据当前时间和课程时间段判断课程状态 * @param string $currentTime 当前时间 H:i:s * @param string $startTime 开始时间 H:i:s * @param string $endTime 结束时间 H:i:s * @return string */ private function determineStatus($currentTime, $startTime, $endTime) { $currentTimestamp = strtotime($currentTime); $startTimestamp = strtotime($startTime); $endTimestamp = strtotime($endTime); // 如果当前时间在课程时间段内,状态为进行中 if ($currentTimestamp >= $startTimestamp && $currentTimestamp <= $endTimestamp) { return 'ongoing'; } // 如果课程已结束,状态为已完成 if ($currentTimestamp > $endTimestamp) { return 'completed'; } // 如果距离开始时间不足6小时,状态为即将开始 $timeDiff = $startTimestamp - $currentTimestamp; if ($timeDiff <= 6 * 3600 && $timeDiff > 0) { // 6小时 = 6 * 60 * 60 秒 return 'upcoming'; } // 其他情况为待安排 return 'pending'; } }