'skipped', 'reason' => 'locked']; } // 创建锁文件 file_put_contents($lockFile, time()); try { Log::write('开始执行自动排课任务'); // 检查今天是否已经执行过 $today = date('Y-m-d'); $executionFlag = runtime_path() . 'course_schedule_' . $today . '.flag'; if (file_exists($executionFlag)) { Log::write('今天已经执行过自动排课,跳过'); return ['status' => 'skipped', 'reason' => 'already_executed_today']; } // 执行排课任务 $result = $this->copyCoursesToFutureDays(30); // 创建执行标记文件 file_put_contents($executionFlag, time()); Log::write('自动排课任务执行完成'); return $result; } finally { // 删除锁文件 if (file_exists($lockFile)) { unlink($lockFile); } } } /** * 将今天的自动排课复制到未来指定天数 * @param int $days 未来天数 * @return array 处理结果 */ public function copyCoursesToFutureDays($days = 30) { // 获取基准日期 - 使用最近一个工作日的自动排课作为模板 $baseDate = $this->getLatestAutoScheduleDate(); if (empty($baseDate)) { Log::write('未找到自动排课模板数据'); return [ 'status' => 'failed', 'reason' => 'no_template_data', 'total' => 0, 'inserted' => 0, 'skipped' => 0 ]; } // 获取基准日期的所有auto_schedule=1的课程 $autoSchedules = CourseSchedule::where('auto_schedule', 1) ->where('course_date', $baseDate) ->select(); Log::write('找到' . count($autoSchedules) . '个基于日期 ' . $baseDate . ' 的自动排课模板'); $results = [ 'status' => 'success', 'base_date' => $baseDate, 'total' => count($autoSchedules), 'inserted' => 0, 'skipped' => 0, 'details' => [] ]; if (count($autoSchedules) == 0) { Log::write('没有找到自动排课模板,跳过执行'); return $results; } // 遍历每个课程,复制到未来30天 foreach ($autoSchedules as $schedule) { $courseResults = $this->copyCourseToFutureDays($schedule, $days); $results['inserted'] += $courseResults['inserted']; $results['skipped'] += $courseResults['skipped']; $results['details'][] = $courseResults; } Log::write('自动排课完成,共插入' . $results['inserted'] . '个课程,跳过' . $results['skipped'] . '个已存在课程'); return $results; } /** * 将单个课程复制到未来指定天数 * @param CourseSchedule $schedule 课程安排 * @param int $days 未来天数 * @return array 处理结果 */ protected function copyCourseToFutureDays(CourseSchedule $schedule, $days) { $result = [ 'course_id' => $schedule->course_id, 'campus_id' => $schedule->campus_id, 'venue_id' => $schedule->venue_id, 'time_slot' => $schedule->time_slot, 'inserted' => 0, 'skipped' => 0, 'dates' => [] ]; // 从明天开始,复制到未来指定天数 for ($i = 1; $i <= $days; $i++) { // 计算目标日期 $targetDate = date('Y-m-d', strtotime("+{$i} days")); // 检查该日期是否有相同的课程安排 $exists = $this->checkCourseExists($schedule, $targetDate); if (!$exists) { // 如果不存在,则插入新的课程安排 $newSchedule = $this->createNewSchedule($schedule, $targetDate); $result['inserted']++; $result['dates'][] = [ 'date' => $targetDate, 'status' => 'inserted', 'id' => $newSchedule->id ]; } else { $result['skipped']++; $result['dates'][] = [ 'date' => $targetDate, 'status' => 'skipped' ]; } } return $result; } /** * 处理自动排课数据,按月份检查并插入不存在的课程 * @param int $month 月份(1-12) * @param int $year 年份 * @return array 处理结果 */ public function processAutoSchedule($month, $year) { // 获取所有auto_schedule=1的课程 $autoSchedules = CourseSchedule::where('auto_schedule', 1)->where('course_date', date('Y-m-d'))->select(); $results = []; foreach ($autoSchedules as $schedule) { // 构造课程日期(基于给定的月份和年份) $courseDate = $this->getCourseDate($schedule->course_date, $month, $year); // 检查该月份是否有相同的课程安排 $exists = $this->checkCourseExists($schedule, $courseDate); if (!$exists) { // 如果不存在,则插入新的课程安排 $newSchedule = $this->createNewSchedule($schedule, $courseDate); $results[] = [ 'status' => 'inserted', 'schedule' => $newSchedule ]; } else { $results[] = [ 'status' => 'exists', 'schedule' => $schedule ]; } } return $results; } /** * 根据原始课程日期和目标月份、年份计算新的课程日期 * @param string $originalDate 原始课程日期(格式:Y-m-d) * @param int $targetMonth 目标月份 * @param int $targetYear 目标年份 * @return string 新的课程日期 */ protected function getCourseDate($originalDate, $targetMonth, $targetYear) { $date = \DateTime::createFromFormat('Y-m-d', $originalDate); $date->setDate($targetYear, $targetMonth, $date->format('d')); return $date->format('Y-m-d'); } /** * 检查指定日期是否有相同的课程安排 * @param CourseSchedule $schedule 原始课程安排 * @param string $courseDate 课程日期 * @return bool 是否存在 */ protected function checkCourseExists(CourseSchedule $schedule, $courseDate) { $exists = CourseSchedule::where(function ($query) use ($schedule, $courseDate) { $query->where('campus_id', $schedule->campus_id) ->where('venue_id', $schedule->venue_id) ->where('course_date', $courseDate) ->where('time_slot', $schedule->time_slot) ->where('course_id', $schedule->course_id); })->count(); return $exists > 0; } /** * 创建新的课程安排 * @param CourseSchedule $schedule 原始课程安排 * @param string $courseDate 课程日期 * @return CourseSchedule 新创建的课程安排 */ protected function createNewSchedule(CourseSchedule $schedule, $courseDate) { $newSchedule = new CourseSchedule(); $newSchedule->campus_id = $schedule->campus_id; $newSchedule->venue_id = $schedule->venue_id; $newSchedule->course_date = $courseDate; $newSchedule->time_slot = $schedule->time_slot; $newSchedule->course_id = $schedule->course_id; $newSchedule->auto_schedule = 1; $newSchedule->created_by = 'system'; // 复制其他所有字段(除了id和主键相关字段) $attributes = $schedule->toArray(); foreach ($attributes as $key => $value) { // 跳过id和主键相关字段 if ($key !== 'id' && $key !== 'course_date' && $key !== 'auto_schedule') { $newSchedule->$key = $value; } } $newSchedule->save(); return $newSchedule; } /** * 获取最近一个有自动排课数据的日期 * @return string|null 最近的自动排课日期 */ protected function getLatestAutoScheduleDate() { // 查找最近7天内有自动排课的日期 $latestDate = CourseSchedule::where('auto_schedule', 1) ->where('course_date', '>=', date('Y-m-d', strtotime('-7 days'))) ->where('course_date', '<=', date('Y-m-d')) ->order('course_date', 'desc') ->value('course_date'); if ($latestDate) { Log::write('使用日期 ' . $latestDate . ' 作为自动排课模板'); return $latestDate; } // 如果最近7天没有,则查找历史数据中最新的 $latestDate = CourseSchedule::where('auto_schedule', 1) ->order('course_date', 'desc') ->value('course_date'); if ($latestDate) { Log::write('使用历史日期 ' . $latestDate . ' 作为自动排课模板'); return $latestDate; } return null; } }