processExpiredCourses(); // 处理孩子的固定课 $warningResult = $this->processStudentCourses(); Log::write('课程有效状态检查任务执行完成-' . print_r([ 'expired_courses' => $expiredResult['count'], 'warning_courses' => $warningResult['count'], ], true)); return true; } catch (\Exception $e) { Log::write('课程有效状态检查任务执行失败:' . $e->getMessage()); throw $e; } } /** * 处理课程的状态 * 根据school_course_schedule表的course_date和time_slot更新课程状态 * @return array 处理结果 */ private function processExpiredCourses() { $currentDate = date('Y-m-d'); $currentTime = date('H:i:s'); $currentDateTime = date('Y-m-d H:i:s'); $count = 0; try { // 1. 更新已结束的课程 - course_date小于当前日期 $completedCount = Db::name('school_course_schedule') ->where('course_date', '<', $currentDate) ->where('status', '<>', 'completed') ->update([ 'status' => 'completed', 'updated_at' => $currentDateTime ]); Log::write("更新已结束课程数量: {$completedCount}"); $count += $completedCount; // 2. 处理今天的课程,根据time_slot判断状态 $todaySchedules = Db::name('school_course_schedule') ->where('course_date', $currentDate) ->where('status', '<>', 'completed') ->select(); foreach ($todaySchedules as $schedule) { $newStatus = $this->calculateCourseStatus($schedule['time_slot'], $currentTime); if ($newStatus && $newStatus != $schedule['status']) { Db::name('school_course_schedule') ->where('id', $schedule['id']) ->update([ 'status' => $newStatus, 'updated_at' => $currentDateTime ]); $count++; Log::write("更新课程状态: ID {$schedule['id']}, 时间段 {$schedule['time_slot']}, 状态 {$schedule['status']} -> {$newStatus}"); } } } catch (\Exception $e) { Log::write('处理课程状态失败: ' . $e->getMessage()); throw $e; } return ['count' => $count]; } /** * 处理学员固定课的安排 * 查看school_person_course_schedule表中schedule_type=2且person_type=student的课程 * 自动为下周相同时间新增上课记录 * @return array 处理结果 */ private function processStudentCourses() { $currentDate = date('Y-m-d'); $currentDateTime = date('Y-m-d H:i:s'); $count = 0; try { // 查找学员的固定课程安排 $studentFixedCourses = Db::name('school_person_course_schedule') ->where('schedule_type', 2) ->where('person_type', 'student') ->where('status', 1) // 假设1为有效状态 ->select(); foreach ($studentFixedCourses as $studentCourse) { // 通过schedule_id获取课程安排信息 $courseSchedule = Db::name('school_course_schedule') ->where('id', $studentCourse['schedule_id']) ->find(); if (!$courseSchedule) { continue; } // 计算下周同一天的日期 $courseDate = $courseSchedule['course_date']; $dayOfWeek = date('w', strtotime($courseDate)); // 0(周日)到6(周六) $nextWeekDate = $this->getNextWeekSameDay($courseDate); // 检查下周那天是否有相同时间段的课程安排 $nextWeekSchedule = Db::name('school_course_schedule') ->where('course_date', $nextWeekDate) ->where('time_slot', $courseSchedule['time_slot']) ->where('venue_id', $courseSchedule['venue_id']) // 同一场地 ->find(); if ($nextWeekSchedule) { // 检查该学员是否已经有下周的上课记录 $existingRecord = Db::name('school_person_course_schedule') ->where('person_id', $studentCourse['person_id']) ->where('schedule_id', $nextWeekSchedule['id']) ->where('person_type', 'student') ->count(); if ($existingRecord == 0) { // 为学员新增下周的上课记录 $newRecord = [ 'person_id' => $studentCourse['person_id'], 'schedule_id' => $nextWeekSchedule['id'], 'person_type' => 'student', 'schedule_type' => 2, // 固定课 'status' => 1, 'created_at' => $currentDateTime, 'updated_at' => $currentDateTime ]; // 复制其他可能的字段 if (isset($studentCourse['course_id'])) { $newRecord['course_id'] = $studentCourse['course_id']; } if (isset($studentCourse['venue_id'])) { $newRecord['venue_id'] = $studentCourse['venue_id']; } Db::name('school_person_course_schedule')->insert($newRecord); $count++; Log::write("为学员新增下周固定课: 学员ID {$studentCourse['person_id']}, 日期 {$nextWeekDate}, 时间段 {$courseSchedule['time_slot']}"); } } else { Log::write("下周无对应课程安排,跳过: 日期 {$nextWeekDate}, 时间段 {$courseSchedule['time_slot']}"); } } } catch (\Exception $e) { Log::write('处理学员固定课安排失败: ' . $e->getMessage()); throw $e; } return ['count' => $count]; } /** * 根据时间段和当前时间计算课程状态 * @param string $timeSlot 时间段,格式如 "11:30-12:30" * @param string $currentTime 当前时间,格式如 "14:30:00" * @return string|null 课程状态:upcoming, ongoing, completed 或 null(无需更新) */ private function calculateCourseStatus($timeSlot, $currentTime) { if (empty($timeSlot)) { return null; } // 解析时间段,格式如 "11:30-12:30" $timeParts = explode('-', $timeSlot); if (count($timeParts) != 2) { Log::write("时间段格式错误: {$timeSlot}"); return null; } $startTime = trim($timeParts[0]) . ':00'; // 转换为 "11:30:00" $endTime = trim($timeParts[1]) . ':00'; // 转换为 "12:30:00" $currentTimestamp = strtotime($currentTime); $startTimestamp = strtotime($startTime); $endTimestamp = strtotime($endTime); $sixHoursBeforeStart = $startTimestamp - (6 * 3600); // 开始时间前6小时 if ($currentTimestamp <= $sixHoursBeforeStart) { // 当前时间距离开始时间超过6小时,不需要更新状态 return null; } elseif ($currentTimestamp <= $startTimestamp) { // 当前时间在开始前6小时内,状态为即将开始 return 'upcoming'; } elseif ($currentTimestamp >= $startTimestamp && $currentTimestamp <= $endTimestamp) { // 当前时间在课程时间范围内,状态为进行中 return 'ongoing'; } elseif ($currentTimestamp > $endTimestamp) { // 当前时间已过结束时间,状态为已结束 return 'completed'; } return null; } /** * 计算下周同一天的日期 * @param string $courseDate 课程日期,格式如 "2025-01-08" * @return string 下周同一天的日期 */ private function getNextWeekSameDay($courseDate) { $timestamp = strtotime($courseDate); $nextWeekTimestamp = $timestamp + (7 * 24 * 3600); // 加7天 return date('Y-m-d', $nextWeekTimestamp); } /** * 发送课程即将过期的警告通知 * @param Course $course 课程对象 */ protected function sendExpiryWarning($course) { // 这里可以实现具体的通知逻辑 // 比如发送邮件、短信、系统内通知等 Log::write("发送过期提醒通知:课程 {$course->course_name} 将在 {$course->valid_until} 过期"); // 示例:可以调用通知服务 // NotificationService::send([ // 'type' => 'course_expiry_warning', // 'course_id' => $course->id, // 'message' => "您的课程《{$course->course_name}》将在{$course->valid_until}过期" // ]); } }