号源排序

main
鹿和sa0ChunLuyu 2 weeks ago
parent 3de23f3da3
commit 4286272d5d

@ -402,23 +402,92 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster
{ {
$dateRange = request('dateRange'); $dateRange = request('dateRange');
$HolidayEnable = request('HolidayEnable', 1); $HolidayEnable = request('HolidayEnable', 1);
$autoMode = request('autoMode', 1);
$userid = 0; $userid = 0;
try { try {
// 1. 查询所有资源,按 time_mode 分组 if ($autoMode == 1) {
// 自动模式:按顶级科室的 auto_gen_days 生成
$depts = DB::table('s_department')
->where('pid', 0)
->where('is_del', 0)
->where('appointment_enabled', 1)
->where('auto_gen_days', '>', 0)
->get();
$allResults = [];
$allTotal = 0;
foreach ($depts as $dept) {
$today = date('Y-m-d');
$endDate = date('Y-m-d', strtotime("+{$dept->auto_gen_days} days"));
$deptDateRange = [$today, $endDate];
$resources = DB::table('s_department_resources')
->where('department_id', $dept->id)
->where('is_del', 0)
->get()
->groupBy('time_mode');
if ($resources->isEmpty()) {
continue;
}
$res = $this->generateBatchForResources(
$resources, $deptDateRange, $HolidayEnable, $userid, $rosterService
);
$allResults = array_merge($allResults, $res['details']);
$allTotal += $res['total_count'];
}
$successCount = collect($allResults)->where('status', 'success')->count();
$failedCount = collect($allResults)->where('status', 'failed')->count();
return \Yz::Return(
true,
"自动生成完成,共 {$allTotal} 条 (成功: {$successCount} 资源, 失败: {$failedCount} 资源)",
[
'total_count' => $allTotal,
'success_count' => $successCount,
'failed_count' => $failedCount,
'details' => $allResults
]
);
} else {
// 手动模式:使用入参 dateRange走原有逻辑
$resources = DB::table('s_department_resources') $resources = DB::table('s_department_resources')
->where(['is_del' => 0]) ->where(['is_del' => 0])
->get() ->get()
->groupBy('time_mode'); ->groupBy('time_mode');
$res = $this->generateBatchForResources(
$resources, $dateRange, $HolidayEnable, $userid, $rosterService
);
return \Yz::Return(
true,
"批量生成完成,共 {$res['total_count']} 条 (成功: {$res['success_count']} 资源, 失败: {$res['failed_count']} 资源)",
$res
);
}
} catch (\Exception $e) {
return \Yz::echoError1($e->getMessage());
}
}
/**
* 批量生成号源(核心逻辑,按资源分组遍历)
*/
private function generateBatchForResources($resources, $dateRange, $HolidayEnable, $userid, RosterService $rosterService)
{
$results = []; $results = [];
$totalCount = 0; $totalCount = 0;
// 2. 遍历不同 time_mode 的资源
foreach ($resources as $timeMode => $resourceGroup) { foreach ($resources as $timeMode => $resourceGroup) {
$resourceIds = $resourceGroup->pluck('id')->toArray(); $resourceIds = $resourceGroup->pluck('id')->toArray();
// 3. 根据 time_mode 查询对应的模板
$templatesQuery = DB::table('s_source_roster') $templatesQuery = DB::table('s_source_roster')
->leftJoin('s_department_resources', 's_source_roster.resources_id', '=', 's_department_resources.id') ->leftJoin('s_department_resources', 's_source_roster.resources_id', '=', 's_department_resources.id')
->select( ->select(
@ -431,20 +500,17 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster
->where(['s_source_roster.status' => 1, 's_source_roster.is_del' => 0]); ->where(['s_source_roster.status' => 1, 's_source_roster.is_del' => 0]);
if ($timeMode == 1) { if ($timeMode == 1) {
// 时令资源: 只查询 type=1 或 2 的模板
$templatesQuery->whereIn('s_source_roster.type', [1, 2]); $templatesQuery->whereIn('s_source_roster.type', [1, 2]);
} else { } else {
// 普通资源: 只查询 type=0 的模板
$templatesQuery->where('s_source_roster.type', 0); $templatesQuery->where('s_source_roster.type', 0);
} }
$allModels = $templatesQuery->get(); $allModels = $templatesQuery->get();
if ($allModels->isEmpty()) { if ($allModels->isEmpty()) {
continue; // 该 time_mode 下没有模板,跳过 continue;
} }
// 4. 时令模板根据资源的 time_range 进行匹配
if ($timeMode == 1) { if ($timeMode == 1) {
$validTemplates = collect(); $validTemplates = collect();
$startDate = new DateTime($dateRange[0]); $startDate = new DateTime($dateRange[0]);
@ -455,7 +521,6 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster
foreach ($allModels as $model) { foreach ($allModels as $model) {
$resource = $resourceGroup->where('id', $model->resources_id)->first(); $resource = $resourceGroup->where('id', $model->resources_id)->first();
// 检查日期是否在时令范围内
if ($this->isDateInSeasonalRange($currentDate, $model->type, $resource)) { if ($this->isDateInSeasonalRange($currentDate, $model->type, $resource)) {
if (!$validTemplates->contains('id', $model->id)) { if (!$validTemplates->contains('id', $model->id)) {
$validTemplates->push($model); $validTemplates->push($model);
@ -468,11 +533,10 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster
$allModels = $validTemplates; $allModels = $validTemplates;
if ($allModels->isEmpty()) { if ($allModels->isEmpty()) {
continue; // 没有匹配的时令模板,跳过 continue;
} }
} }
// 5. 按资源分组,按 date_type 细分,循环调用 generatePlans
$groupedByResource = $allModels->groupBy('resources_id'); $groupedByResource = $allModels->groupBy('resources_id');
foreach ($groupedByResource as $resourcesId => $models) { foreach ($groupedByResource as $resourcesId => $models) {
@ -513,24 +577,15 @@ public function BatchGenerateByDateRange(Request $request, RosterService $roster
} }
} }
// 6. 统计结果
$successCount = collect($results)->where('status', 'success')->count(); $successCount = collect($results)->where('status', 'success')->count();
$failedCount = collect($results)->where('status', 'failed')->count(); $failedCount = collect($results)->where('status', 'failed')->count();
return \Yz::Return( return [
true,
"批量生成完成,共 {$totalCount} 条 (成功: {$successCount} 资源, 失败: {$failedCount} 资源)",
[
'total_count' => $totalCount, 'total_count' => $totalCount,
'success_count' => $successCount, 'success_count' => $successCount,
'failed_count' => $failedCount, 'failed_count' => $failedCount,
'details' => $results 'details' => $results
] ];
);
} catch (\Exception $e) {
return \Yz::echoError1($e->getMessage());
}
} }
/** /**

@ -257,6 +257,101 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
$pp = array_merge($pl1, $pl2); $pp = array_merge($pl1, $pl2);
// 诊室排序:按最早可用时间升序 → 最早时段剩余号源降序 → 随机
$grouped = [];
$nowTimestamp = time();
foreach ($pp as $plan) {
$name = $plan->department_resources_name;
if (!isset($grouped[$name])) {
$grouped[$name] = ['plans' => [], 'remaining' => 0, 'earliest_remaining' => 0];
}
$grouped[$name]['plans'][] = $plan;
// 累计全天总剩余
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0) - ($plan->locked_count ?? 0);
$grouped[$name]['remaining'] += max($remaining, 0);
// 判断是否未过期,收集最早开始时间及该时段剩余
$endDateTime = $plan->date . ' ' . ($plan->end_time ?? '23:59:59');
if (strtotime($endDateTime) > $nowTimestamp) {
$startDateTime = $plan->date . ' ' . ($plan->begin_time ?? '00:00:00');
$ts = strtotime($startDateTime);
if (!isset($grouped[$name]['earliest']) || $ts < $grouped[$name]['earliest']) {
$grouped[$name]['earliest'] = $ts;
$grouped[$name]['earliest_remaining'] = max($remaining, 0);
} elseif ($ts == $grouped[$name]['earliest']) {
// 同一 earliest 时段,累加该时段剩余
$grouped[$name]['earliest_remaining'] += max($remaining, 0);
}
}
}
// 诊室排序:先转为索引数组,再手动排序
$grouped = array_values($grouped);
if (count($grouped) >= 2) {
// 按规则排序:有可用号源优先 → 最早时间升序 → 剩余号源降序 → 随机
$hasEarliest = [];
foreach ($grouped as $idx => $g) {
$hasEarliest[$idx] = isset($g['earliest']);
}
// 简单冒泡排序(只有 2 个诊室时足够)
for ($i = 0; $i < count($grouped) - 1; $i++) {
for ($j = $i + 1; $j < count($grouped); $j++) {
$a = $grouped[$i];
$b = $grouped[$j];
$aHas = isset($a['earliest']);
$bHas = isset($b['earliest']);
$swap = false;
if ($aHas != $bHas) {
$swap = $bHas; // 有可用号源的排前面
} elseif ($aHas) {
if ($a['earliest'] != $b['earliest']) {
$swap = ($a['earliest'] > $b['earliest']); // 最早时间升序
} elseif ($a['earliest_remaining'] != $b['earliest_remaining']) {
$swap = ($a['earliest_remaining'] < $b['earliest_remaining']); // 最早时段剩余号源降序
} else {
$swap = (rand(0, 1) == 1); // 随机
}
} else {
$swap = (rand(0, 1) == 1); // 都无可用号源,随机
}
if ($swap) {
$temp = $grouped[$i];
$grouped[$i] = $grouped[$j];
$grouped[$j] = $temp;
}
}
}
}
// 按诊室排序后,同诊室 plan 按时间排序,最后打散
$pp = [];
$debugGroupedOrder = [];
foreach ($grouped as $g) {
$plans = $g['plans'];
$debugGroupedOrder[] = [
'name' => $plans[0]->department_resources_name ?? '',
'earliest' => isset($g['earliest']) ? date('Y-m-d H:i:s', $g['earliest']) : null,
'remaining' => $g['remaining'],
];
usort($plans, function($a, $b) {
$timeA = $a->date . ' ' . ($a->begin_time ?? '00:00:00');
$timeB = $b->date . ' ' . ($b->begin_time ?? '00:00:00');
if ($timeA !== $timeB) {
return $timeA <=> $timeB;
}
$availableA = ($a->count ?? 0) - ($a->used_count ?? 0) - ($a->locked_count ?? 0);
$availableB = ($b->count ?? 0) - ($b->used_count ?? 0) - ($b->locked_count ?? 0);
return ($availableB <=> $availableA);
});
foreach ($plans as $plan) {
$pp[] = $plan;
}
}
return \Yz::Return(true, '查询完成', [ return \Yz::Return(true, '查询完成', [
'today_date' => date("Y-m-d"), 'today_date' => date("Y-m-d"),
@ -272,6 +367,7 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
'debug_allRids' => $debugAllRids ?? [], 'debug_allRids' => $debugAllRids ?? [],
'debug_skipped' => $debugSkipped ?? [], 'debug_skipped' => $debugSkipped ?? [],
'debug_passedRids' => array_values(array_unique($debugPassed ?? [])), 'debug_passedRids' => array_values(array_unique($debugPassed ?? [])),
'debug_grouped_order' => $debugGroupedOrder ?? [],
]); ]);
} }

Loading…
Cancel
Save