From e15d1c9926c093e2bc284974243907063058b6bc Mon Sep 17 00:00:00 2001 From: sa0ChunLuyu Date: Sun, 26 Jul 2026 13:31:19 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A2=84=E7=BA=A6=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/Admin/YeWu/PlanListService.php | 135 +++++++++++++++++- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/Laravel/app/Services/Admin/YeWu/PlanListService.php b/Laravel/app/Services/Admin/YeWu/PlanListService.php index 45699e9..11f042b 100644 --- a/Laravel/app/Services/Admin/YeWu/PlanListService.php +++ b/Laravel/app/Services/Admin/YeWu/PlanListService.php @@ -434,12 +434,44 @@ public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appoint $endDate = new DateTime(); $endDate->modify('+' . $dateRange . ' day'); + $debug = [ + 'input_params' => [ + 'type' => $type, + 'type_type' => gettype($type), + 'type_length' => is_string($type) ? strlen($type) : null, + 'type_hex' => is_string($type) ? bin2hex($type) : null, + 'regnum' => $regnum, + 'entrustid_count' => count($entrustids), + 'entrustid' => $entrustids, + 'episodeid' => $episodeid, + 'appointment_type' => $appointment_type, + 'items_count' => count($items), + 'item_ids' => array_column($items, 'id'), + 'item_entrust_ids' => array_column($items, 'entrust_id'), + 'occupied_plan_ids' => $occupied_plan_ids, + 'startDate' => $startDate->format('Y-m-d'), + 'endDate' => $endDate->format('Y-m-d'), + 'scope' => $scope, + ], + 'dispatch' => null, + 'trace' => [], + ]; + if ($type === 'full_day') { - return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids); + $debug['dispatch'] = 'doFullDayAssign'; + $response = $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids); + $response['debug'] = $debug; + return $response; } elseif ($type === 'same_day_slot') { - return $this->doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids); + $debug['dispatch'] = 'doSameDaySlotAssign'; + $response = $this->doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids, $debug); + $response['debug'] = $debug; + return $response; } else { - return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids); + $debug['dispatch'] = 'doOptimalTimeAssign (兜底)'; + $response = $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids); + $response['debug'] = $debug; + return $response; } } @@ -630,18 +662,31 @@ private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $ep } // 同一天同一时间段分配:所有 item 必须在同一天且同一时间段完成 - private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = []) + private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [], &$debug = []) { // 按科室分组 $deptGroups = $this->groupItemsByDept($items); if (empty($deptGroups)) { + $debug['error'] = 'groupItemsByDept 返回空分组'; return \Yz::Return(true, '获取成功', []); } + $deptGroupSummary = []; + foreach ($deptGroups as $deptCode => $group) { + $deptGroupSummary[$deptCode] = [ + 'entrustid_count' => count($group['entrustids']), + 'entrustids' => $group['entrustids'], + 'item_count' => count($group['items']), + 'item_ids' => array_column($group['items'], 'id'), + ]; + } + $debug['deptGroups'] = $deptGroupSummary; + $currentDate = clone $startDate; while ($currentDate <= $endDate) { $nowdate = $currentDate->format('Y-m-d'); + $dayTrace = ['date' => $nowdate, 'steps' => []]; // 收集所有科室在该日期的可用号源 $allDeptPlans = []; @@ -650,15 +695,26 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, foreach ($deptGroups as $deptCode => $group) { $availablePlans = $this->getAvailablePlansForDate($regnum, $group['entrustids'], $episodeid, $appointment_type, $nowdate, $scope, $userDeptId); + $planInfo = [ + 'deptCode' => $deptCode, + 'raw_plan_count' => count($availablePlans), + 'raw_plan_ids' => array_map(function($p) { return $p->id; }, $availablePlans), + 'raw_plan_times' => array_map(function($p) { return $p->begin_time . '-' . $p->end_time; }, $availablePlans), + ]; + // 过滤已占用的号源 if (!empty($occupied_plan_ids)) { $availablePlans = array_filter($availablePlans, function($plan) use ($occupied_plan_ids) { return !in_array($plan->id, $occupied_plan_ids); }); $availablePlans = array_values($availablePlans); + $planInfo['after_occupy_filter_count'] = count($availablePlans); + $planInfo['after_occupy_filter_ids'] = array_map(function($p) { return $p->id; }, $availablePlans); } if (empty($availablePlans)) { + $planInfo['no_plans'] = true; + $dayTrace['steps'][] = $planInfo; $allAssigned = false; break; } @@ -667,6 +723,8 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, } if (!$allAssigned) { + $dayTrace['result'] = 'skip: 有科室无可用号源'; + $debug['trace'][] = $dayTrace; $currentDate->modify('+1 day'); continue; } @@ -686,13 +744,45 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, } } + $slotGroupSummary = []; + foreach ($slotGroups as $slotKey => $deptPlans) { + $entry = []; + foreach ($deptPlans as $deptCode => $plans) { + $entry[$deptCode] = [ + 'count' => count($plans), + 'plan_ids' => array_map(function($p) { return $p->id; }, $plans), + 'capacities' => array_map(function($p) { return ($p->count ?? 0) - ($p->used_count ?? 0); }, $plans), + ]; + } + $missingDepts = []; + foreach ($deptGroups as $deptCode => $group) { + if (!isset($deptPlans[$deptCode])) { + $missingDepts[] = $deptCode; + } + } + $entry['missing_depts'] = $missingDepts; + $slotGroupSummary[$slotKey] = $entry; + } + + $dayTrace['steps'][] = [ + 'action' => 'slot_grouping', + 'slot_count' => count($slotGroups), + 'slot_keys' => array_keys($slotGroups), + 'slot_details' => $slotGroupSummary, + ]; + // 对每个时间段,尝试分配所有项目 foreach ($slotGroups as $slotKey => $deptPlans) { $result = []; $allInSlot = true; + $slotTrace = ['slot' => $slotKey, 'dept_assignments' => []]; foreach ($deptGroups as $deptCode => $group) { if (!isset($deptPlans[$deptCode])) { + $slotTrace['dept_assignments'][] = [ + 'deptCode' => $deptCode, + 'result' => 'missing_in_slot', + ]; $allInSlot = false; break; } @@ -700,6 +790,7 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $availablePlans = $deptPlans[$deptCode]; $usedCapacity = []; $assignedPlans = []; + $deptAssignTrace = ['deptCode' => $deptCode, 'items' => []]; foreach ($group['items'] as $item) { $assigned = false; @@ -708,7 +799,17 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0); $used = $usedCapacity[$planId] ?? 0; - if (($remaining - $used) <= 0) continue; + if (($remaining - $used) <= 0) { + $deptAssignTrace['items'][] = [ + 'item_id' => $item['id'], + 'entrust_id' => $item['entrust_id'], + 'result' => 'capacity_exhausted', + 'plan_id' => $planId, + 'remaining' => $remaining, + 'used_in_session' => $used, + ]; + continue; + } $result[] = [ 'id' => $item['id'], @@ -724,24 +825,48 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, 'begin_time' => $plan->begin_time, 'end_time' => $plan->end_time ]; + $deptAssignTrace['items'][] = [ + 'item_id' => $item['id'], + 'entrust_id' => $item['entrust_id'], + 'result' => 'assigned', + 'plan_id' => $planId, + ]; $assigned = true; break; } if (!$assigned) { + $deptAssignTrace['items'][] = [ + 'item_id' => $item['id'], + 'entrust_id' => $item['entrust_id'], + 'result' => 'no_available_plan', + ]; $allInSlot = false; break 2; } } + $slotTrace['dept_assignments'][] = $deptAssignTrace; } if ($allInSlot) { + $slotTrace['result'] = 'success'; + $dayTrace['steps'][] = $slotTrace; + $dayTrace['result'] = 'success'; + $debug['trace'][] = $dayTrace; return \Yz::Return(true, '获取成功', $result); } + + $slotTrace['result'] = 'failed'; + $slotTrace['partial_result_count'] = count($result); + $slotTrace['partial_result'] = $result; + $dayTrace['steps'][] = $slotTrace; } + $dayTrace['result'] = 'all_slots_failed'; + $debug['trace'][] = $dayTrace; $currentDate->modify('+1 day'); } + $debug['result'] = 'no_solution_in_range'; return \Yz::Return(true, '获取成功', []); }