|
|
|
|
@ -434,44 +434,12 @@ 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') {
|
|
|
|
|
$debug['dispatch'] = 'doFullDayAssign';
|
|
|
|
|
$response = $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
$response['debug'] = $debug;
|
|
|
|
|
return $response;
|
|
|
|
|
return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
} elseif ($type === 'same_day_slot') {
|
|
|
|
|
$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;
|
|
|
|
|
return $this->doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
} else {
|
|
|
|
|
$debug['dispatch'] = 'doOptimalTimeAssign (兜底)';
|
|
|
|
|
$response = $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
$response['debug'] = $debug;
|
|
|
|
|
return $response;
|
|
|
|
|
return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -662,31 +630,18 @@ 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 = [], &$debug = [])
|
|
|
|
|
private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [])
|
|
|
|
|
{
|
|
|
|
|
// 按科室分组
|
|
|
|
|
$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 = [];
|
|
|
|
|
@ -695,26 +650,15 @@ 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;
|
|
|
|
|
}
|
|
|
|
|
@ -723,8 +667,6 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$allAssigned) {
|
|
|
|
|
$dayTrace['result'] = 'skip: 有科室无可用号源';
|
|
|
|
|
$debug['trace'][] = $dayTrace;
|
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
@ -744,45 +686,13 @@ 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;
|
|
|
|
|
}
|
|
|
|
|
@ -790,7 +700,6 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids,
|
|
|
|
|
$availablePlans = $deptPlans[$deptCode];
|
|
|
|
|
$usedCapacity = [];
|
|
|
|
|
$assignedPlans = [];
|
|
|
|
|
$deptAssignTrace = ['deptCode' => $deptCode, 'items' => []];
|
|
|
|
|
|
|
|
|
|
foreach ($group['items'] as $item) {
|
|
|
|
|
$assigned = false;
|
|
|
|
|
@ -799,17 +708,7 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids,
|
|
|
|
|
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0);
|
|
|
|
|
$used = $usedCapacity[$planId] ?? 0;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
if (($remaining - $used) <= 0) continue;
|
|
|
|
|
|
|
|
|
|
$result[] = [
|
|
|
|
|
'id' => $item['id'],
|
|
|
|
|
@ -825,48 +724,24 @@ 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, '获取成功', []);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|