|
|
|
@ -43,18 +43,27 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1,
|
|
|
|
// ==========================================
|
|
|
|
// ==========================================
|
|
|
|
$this->validateTemplates($models);
|
|
|
|
$this->validateTemplates($models);
|
|
|
|
|
|
|
|
|
|
|
|
// ==========================================
|
|
|
|
// 2. 获取节假日列表
|
|
|
|
// 2. 整体校验:资源时段冲突检测
|
|
|
|
|
|
|
|
// ==========================================
|
|
|
|
|
|
|
|
$this->checkResourceTimeConflict($models, $start_date, $end_date);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 获取节假日列表
|
|
|
|
|
|
|
|
$holiday_list = DB::table('s_holiday')
|
|
|
|
$holiday_list = DB::table('s_holiday')
|
|
|
|
->whereBetween('date', $dateRange)
|
|
|
|
->whereBetween('date', $dateRange)
|
|
|
|
->where(['type' => 2])
|
|
|
|
->where(['type' => 2])
|
|
|
|
->pluck('date')
|
|
|
|
->pluck('date')
|
|
|
|
->toArray();
|
|
|
|
->toArray();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ==========================================
|
|
|
|
|
|
|
|
// 3. 整体校验:资源时段冲突检测(先检查再生成)
|
|
|
|
|
|
|
|
// ==========================================
|
|
|
|
|
|
|
|
$conflicts = $this->checkResourceTimeConflict(
|
|
|
|
|
|
|
|
$models, $start_date, $end_date, $dateType, $holidayEnable, $holiday_list
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!empty($conflicts)) {
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
|
|
|
'success' => false,
|
|
|
|
|
|
|
|
'conflicts' => $conflicts,
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$generatedDates = [];
|
|
|
|
$generatedDates = [];
|
|
|
|
$skippedDates = [];
|
|
|
|
$skippedDates = [];
|
|
|
|
$success_count = 0;
|
|
|
|
$success_count = 0;
|
|
|
|
@ -95,26 +104,6 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1,
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- 资源级存在性检查:当天该资源下是否有任何号源 ---
|
|
|
|
|
|
|
|
$resources_id = $models->first()->resources_id;
|
|
|
|
|
|
|
|
$resourceExists = DB::table('s_source_roster_detail')
|
|
|
|
|
|
|
|
->where('resources_id', $resources_id)
|
|
|
|
|
|
|
|
->where('date', $current_date_str)
|
|
|
|
|
|
|
|
->where('is_del', 0)
|
|
|
|
|
|
|
|
->exists();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($resourceExists) {
|
|
|
|
|
|
|
|
foreach ($models as $model) {
|
|
|
|
|
|
|
|
$skippedDates[] = [
|
|
|
|
|
|
|
|
'date' => $current_date_str,
|
|
|
|
|
|
|
|
'template_id' => $model->id,
|
|
|
|
|
|
|
|
'reason' => '已存在',
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
$current_date->modify('+1 day');
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- 获取星期 ---
|
|
|
|
// --- 获取星期 ---
|
|
|
|
$weekday = (int)$current_date->format('w');
|
|
|
|
$weekday = (int)$current_date->format('w');
|
|
|
|
$weekname = $this->getWeekName($weekday);
|
|
|
|
$weekname = $this->getWeekName($weekday);
|
|
|
|
@ -238,45 +227,77 @@ private function validateTemplates($models)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* 资源级别查重:同一资源同一天的时间段不能重叠
|
|
|
|
* 资源级别冲突检测:遍历日期范围内每一天,应用与主循环一致的过滤逻辑,
|
|
|
|
* 同一资源同一天可以有多个不同时段,但是时段不能交差
|
|
|
|
* 检查每个模板的资源在该日期是否存在时段重叠的号源。
|
|
|
|
* 边界判断:不重叠(一个时间点结束,另一个可以开始)
|
|
|
|
* 边界判断:不重叠(一个时间点结束,另一个可以开始)
|
|
|
|
|
|
|
|
* 返回冲突列表,无冲突则返回空数组
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private function checkResourceTimeConflict($models, $startDate, $endDate)
|
|
|
|
private function checkResourceTimeConflict($models, $startDate, $endDate, $dateType, $holidayEnable, $holidayList)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
$startStr = $startDate->format('Y-m-d');
|
|
|
|
$conflicts = [];
|
|
|
|
$endStr = $endDate->format('Y-m-d');
|
|
|
|
$currentDate = clone $startDate;
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($models as $model) {
|
|
|
|
while ($currentDate <= $endDate) {
|
|
|
|
// 查询该资源在日期范围内已存在的排班
|
|
|
|
$dateStr = $currentDate->format('Y-m-d');
|
|
|
|
$existingPlans = DB::table('s_source_roster_detail')
|
|
|
|
|
|
|
|
->where('resources_id', $model->resources_id)
|
|
|
|
// --- 节假日过滤(与主循环一致) ---
|
|
|
|
->where('date', '>=', $startStr)
|
|
|
|
if ($dateType == 2 && !in_array($dateStr, $holidayList)) {
|
|
|
|
->where('date', '<=', $endStr)
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
->where('is_del', 0)
|
|
|
|
continue;
|
|
|
|
->get();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($holidayEnable == 0 && in_array($dateStr, $holidayList)) {
|
|
|
|
foreach ($existingPlans as $existing) {
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
// 检查时间是否重叠(同一天才检查)
|
|
|
|
continue;
|
|
|
|
$existingDate = $existing->date;
|
|
|
|
}
|
|
|
|
// 使用模板的星期作为参考日期
|
|
|
|
|
|
|
|
$templateDate = $this->getTemplateDate($model);
|
|
|
|
$weekday = (int)$currentDate->format('w');
|
|
|
|
if ($existingDate === $templateDate) {
|
|
|
|
$weekname = $this->getWeekName($weekday);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($models as $model) {
|
|
|
|
|
|
|
|
// --- 星期匹配(与主循环一致) ---
|
|
|
|
|
|
|
|
if ($dateType == 1 && isset($model->date_type) && $model->date_type == 1) {
|
|
|
|
|
|
|
|
if ($model->weekname !== $weekname) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- 时令校验(与主循环一致) ---
|
|
|
|
|
|
|
|
$resource = $this->getCachedResource($model->resources_id);
|
|
|
|
|
|
|
|
if (!$this->isDateInSeasonalRange($currentDate, $model->type, $resource)) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// --- 查询该资源在该日期下已有的号源,检查时间段是否重叠 ---
|
|
|
|
|
|
|
|
$existingPlans = DB::table('s_source_roster_detail')
|
|
|
|
|
|
|
|
->where('resources_id', $model->resources_id)
|
|
|
|
|
|
|
|
->where('date', $dateStr)
|
|
|
|
|
|
|
|
->where('is_del', 0)
|
|
|
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach ($existingPlans as $existing) {
|
|
|
|
if ($this->isTimeOverlap(
|
|
|
|
if ($this->isTimeOverlap(
|
|
|
|
$model->begin_time,
|
|
|
|
$model->begin_time,
|
|
|
|
$model->end_time,
|
|
|
|
$model->end_time,
|
|
|
|
$existing->begin_time,
|
|
|
|
$existing->begin_time,
|
|
|
|
$existing->end_time
|
|
|
|
$existing->end_time
|
|
|
|
)) {
|
|
|
|
)) {
|
|
|
|
throw new Exception(
|
|
|
|
$conflicts[] = [
|
|
|
|
"资源ID [{$model->resources_id}] 在 {$existingDate} 存在时段冲突!" .
|
|
|
|
'date' => $dateStr,
|
|
|
|
"新增: {$model->begin_time}-{$model->end_time} " .
|
|
|
|
'weekname' => $weekname,
|
|
|
|
"与已存在的 {$existing->begin_time}-{$existing->end_time} 重叠"
|
|
|
|
'template_id' => $model->id,
|
|
|
|
);
|
|
|
|
'new_time' => $model->begin_time . '-' . $model->end_time,
|
|
|
|
|
|
|
|
'existing_time' => $existing->begin_time . '-' . $existing->end_time,
|
|
|
|
|
|
|
|
'existing_detail_id' => $existing->id,
|
|
|
|
|
|
|
|
'resources_id' => $model->resources_id,
|
|
|
|
|
|
|
|
];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return $conflicts;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@ -347,20 +368,6 @@ private function getCachedResource($resourceId)
|
|
|
|
return $this->resourceCache[$resourceId];
|
|
|
|
return $this->resourceCache[$resourceId];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* 获取模板的日期(用于资源查重时的日期比较)
|
|
|
|
|
|
|
|
* 注意:这里仅用于比较,实际生成时按循环中的日期
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private function getTemplateDate($model)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// 如果模板有固定日期,返回固定日期
|
|
|
|
|
|
|
|
if (isset($model->date)) {
|
|
|
|
|
|
|
|
return $model->date;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// 否则返回 null(表示需要按循环日期比较)
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private function getWeekName($weekday) {
|
|
|
|
private function getWeekName($weekday) {
|
|
|
|
$map = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
|
|
|
$map = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
|
|
|
|
return $map[$weekday] ?? '';
|
|
|
|
return $map[$weekday] ?? '';
|
|
|
|
|