智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

272 lines
11 KiB

<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\job\transfer\schedule;
use app\model\course\Course;
use app\model\course_booking\CourseBooking;
use think\facade\Db;
use core\base\BaseJob;
use think\facade\Log;
/**
* 定时处理课程有效状态任务
* 检查课程的有效期,更新过期课程状态
*/
class CourseValidityJob extends BaseJob
{
/**
* 执行定时任务
* @param mixed ...$data 任务参数
* @return bool 处理结果
*/
public function doJob(...$data)
{
Log::write('开始执行课程有效状态检查任务');
try {
// 处理过期课程
$expiredResult = $this->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}过期"
// ]);
}
}