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.
288 lines
10 KiB
288 lines
10 KiB
<?php
|
|
|
|
namespace app\job\transfer\schedule;
|
|
|
|
use app\model\course_schedule\CourseSchedule;
|
|
use core\base\BaseJob;
|
|
use think\facade\Log;
|
|
|
|
class CourseScheduleJob extends BaseJob
|
|
{
|
|
/**
|
|
* 执行任务,将今天的自动排课复制到未来30天
|
|
* @return array 处理结果
|
|
*/
|
|
public function doJob()
|
|
{
|
|
// 添加执行锁,防止重复执行
|
|
$lockFile = runtime_path() . 'course_schedule.lock';
|
|
if (file_exists($lockFile) && (time() - filemtime($lockFile)) < 600) { // 10分钟锁定
|
|
Log::write('自动排课任务正在执行中,跳过');
|
|
return ['status' => '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;
|
|
}
|
|
}
|