计划生成调整

main
鹿和sa0ChunLuyu 7 days ago
parent b1a952614f
commit d4fefd628f

@ -34,8 +34,12 @@ public function Create(Request $request,RosterService $rosterService)
$HolidayEnable
);
return \Yz::Return(true, '执行完成,共计生成计划 ' . $result['count'] . ' 条', $result);
// 检查是否返回了冲突数据
if (!empty($result['conflicts'])) {
return \Yz::Return(false, '存在时段冲突,生成失败,共 ' . count($result['conflicts']) . ' 条冲突', $result);
}
return \Yz::Return(true, '执行完成,共计生成计划 ' . $result['count'] . ' 条', $result);
} catch (\Exception $e) {
// 捕获服务层抛出的异常,格式化返回给前端
return \Yz::echoError1($e->getMessage());
@ -798,6 +802,11 @@ public function CreateAdmin(Request $request, RosterService $rosterService)
$date_type,
$HolidayEnable
);
// 检查是否返回了冲突数据
if (!empty($result['conflicts'])) {
return \Yz::Return(false, '存在时段冲突,生成失败,共 ' . count($result['conflicts']) . ' 条冲突', $result);
}
return \Yz::Return(true, '执行完成,共计生成计划 ' . $result['count'] . ' 条', $result);
} catch (\Exception $e) {
return \Yz::echoError1($e->getMessage());

@ -43,18 +43,27 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1,
// ==========================================
$this->validateTemplates($models);
// ==========================================
// 2. 整体校验:资源时段冲突检测
// ==========================================
$this->checkResourceTimeConflict($models, $start_date, $end_date);
// 3. 获取节假日列表
// 2. 获取节假日列表
$holiday_list = DB::table('s_holiday')
->whereBetween('date', $dateRange)
->where(['type' => 2])
->pluck('date')
->toArray();
// ==========================================
// 3. 整体校验:资源时段冲突检测(先检查再生成)
// ==========================================
$conflicts = $this->checkResourceTimeConflict(
$models, $start_date, $end_date, $dateType, $holidayEnable, $holiday_list
);
if (!empty($conflicts)) {
return [
'success' => false,
'conflicts' => $conflicts,
];
}
$generatedDates = [];
$skippedDates = [];
$success_count = 0;
@ -95,26 +104,6 @@ public function generatePlans($dateRange, $planModelIds, $userId, $dateType = 1,
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');
$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');
$endStr = $endDate->format('Y-m-d');
$conflicts = [];
$currentDate = clone $startDate;
while ($currentDate <= $endDate) {
$dateStr = $currentDate->format('Y-m-d');
// --- 节假日过滤(与主循环一致) ---
if ($dateType == 2 && !in_array($dateStr, $holidayList)) {
$currentDate->modify('+1 day');
continue;
}
if ($holidayEnable == 0 && in_array($dateStr, $holidayList)) {
$currentDate->modify('+1 day');
continue;
}
$weekday = (int)$currentDate->format('w');
$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', '>=', $startStr)
->where('date', '<=', $endStr)
->where('date', $dateStr)
->where('is_del', 0)
->get();
foreach ($existingPlans as $existing) {
// 检查时间是否重叠(同一天才检查)
$existingDate = $existing->date;
// 使用模板的星期作为参考日期
$templateDate = $this->getTemplateDate($model);
if ($existingDate === $templateDate) {
if ($this->isTimeOverlap(
$model->begin_time,
$model->end_time,
$existing->begin_time,
$existing->end_time
)) {
throw new Exception(
"资源ID [{$model->resources_id}] 在 {$existingDate} 存在时段冲突!" .
"新增: {$model->begin_time}-{$model->end_time} " .
"与已存在的 {$existing->begin_time}-{$existing->end_time} 重叠"
);
$conflicts[] = [
'date' => $dateStr,
'weekname' => $weekname,
'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];
}
/**
* 获取模板的日期(用于资源查重时的日期比较)
* 注意:这里仅用于比较,实际生成时按循环中的日期
*/
private function getTemplateDate($model)
{
// 如果模板有固定日期,返回固定日期
if (isset($model->date)) {
return $model->date;
}
// 否则返回 null表示需要按循环日期比较
return null;
}
private function getWeekName($weekday) {
$map = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
return $map[$weekday] ?? '';

Loading…
Cancel
Save