|
|
|
|
@ -427,74 +427,109 @@ public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appoint
|
|
|
|
|
{
|
|
|
|
|
date_default_timezone_set('PRC');
|
|
|
|
|
$dateRange = config('app.globals.可用号源查询范围');
|
|
|
|
|
$result = [];
|
|
|
|
|
$usedCapacity = []; // 记录已分配的号源容量,key: roster_detail_id, value: 已分配数
|
|
|
|
|
|
|
|
|
|
// 遍历日期范围
|
|
|
|
|
$startDate = new DateTime();
|
|
|
|
|
$endDate = new DateTime();
|
|
|
|
|
$endDate->modify('+' . $dateRange . ' day');
|
|
|
|
|
|
|
|
|
|
if ($type === 'full_day') {
|
|
|
|
|
return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId);
|
|
|
|
|
} else {
|
|
|
|
|
return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 最优时间分配:逐个 item 找最早可用号源,可跨天
|
|
|
|
|
private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId)
|
|
|
|
|
{
|
|
|
|
|
$result = [];
|
|
|
|
|
$usedCapacity = [];
|
|
|
|
|
$assignedPlans = []; // 已分配的时间段 [{resource_name, begin, end}]
|
|
|
|
|
$currentDate = clone $startDate;
|
|
|
|
|
$remainingItems = $items;
|
|
|
|
|
|
|
|
|
|
while ($currentDate <= $endDate) {
|
|
|
|
|
while ($currentDate <= $endDate && !empty($remainingItems)) {
|
|
|
|
|
$nowdate = $currentDate->format('Y-m-d');
|
|
|
|
|
$availablePlans = $this->getAvailablePlansForDate($regnum, $entrustids, $episodeid, $appointment_type, $nowdate, $scope, $userDeptId);
|
|
|
|
|
|
|
|
|
|
// 获取当前日期的可用号源
|
|
|
|
|
$s = $this->GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $nowdate, $scope, $userDeptId);
|
|
|
|
|
|
|
|
|
|
if (!$s['status']) {
|
|
|
|
|
if (empty($availablePlans)) {
|
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$planList = $s['data']['plan_list'] ?? [];
|
|
|
|
|
if (count($planList) == 0) {
|
|
|
|
|
$newRemaining = [];
|
|
|
|
|
foreach ($remainingItems as $item) {
|
|
|
|
|
$assigned = false;
|
|
|
|
|
foreach ($availablePlans as $plan) {
|
|
|
|
|
$planId = $plan->id;
|
|
|
|
|
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0) - ($plan->locked_count ?? 0);
|
|
|
|
|
$used = $usedCapacity[$planId] ?? 0;
|
|
|
|
|
|
|
|
|
|
if (($remaining - $used) <= 0) continue;
|
|
|
|
|
|
|
|
|
|
// 冲突检查:不同排班且时间段重叠
|
|
|
|
|
if ($this->isTimeConflict($assignedPlans, $plan)) continue;
|
|
|
|
|
|
|
|
|
|
// 分配
|
|
|
|
|
$result[] = [
|
|
|
|
|
'id' => $item['id'],
|
|
|
|
|
'plan_id' => $planId,
|
|
|
|
|
'department_resources_name' => $plan->department_resources_name,
|
|
|
|
|
'date' => $plan->date,
|
|
|
|
|
'begin_time' => $plan->begin_time,
|
|
|
|
|
'end_time' => $plan->end_time
|
|
|
|
|
];
|
|
|
|
|
$usedCapacity[$planId] = ($usedCapacity[$planId] ?? 0) + 1;
|
|
|
|
|
$assignedPlans[] = [
|
|
|
|
|
'resource_name' => $plan->department_resources_name,
|
|
|
|
|
'begin_time' => $plan->begin_time,
|
|
|
|
|
'end_time' => $plan->end_time
|
|
|
|
|
];
|
|
|
|
|
$assigned = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!$assigned) {
|
|
|
|
|
$newRemaining[] = $item;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$remainingItems = $newRemaining;
|
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 筛选未过期的、可用的号源
|
|
|
|
|
$nowtime = date('Y-m-d H:i:s');
|
|
|
|
|
$availablePlans = [];
|
|
|
|
|
foreach ($planList as $plan) {
|
|
|
|
|
$planEndTime = $plan->date . ' ' . $plan->end_time;
|
|
|
|
|
if ($planEndTime > $nowtime && $plan->plan_enable) {
|
|
|
|
|
$availablePlans[] = $plan;
|
|
|
|
|
}
|
|
|
|
|
return \Yz::Return(true, '获取成功', $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count($availablePlans) == 0) {
|
|
|
|
|
// 单天全检分配:所有 item 必须在同一天完成
|
|
|
|
|
private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId)
|
|
|
|
|
{
|
|
|
|
|
$currentDate = clone $startDate;
|
|
|
|
|
|
|
|
|
|
while ($currentDate <= $endDate) {
|
|
|
|
|
$nowdate = $currentDate->format('Y-m-d');
|
|
|
|
|
$availablePlans = $this->getAvailablePlansForDate($regnum, $entrustids, $episodeid, $appointment_type, $nowdate, $scope, $userDeptId);
|
|
|
|
|
|
|
|
|
|
if (empty($availablePlans)) {
|
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 按日期、时间排序
|
|
|
|
|
usort($availablePlans, function($a, $b) {
|
|
|
|
|
$timeA = $a->date . ' ' . ($a->begin_time ?? '00:00:00');
|
|
|
|
|
$timeB = $b->date . ' ' . ($b->begin_time ?? '00:00:00');
|
|
|
|
|
return $timeA <=> $timeB;
|
|
|
|
|
});
|
|
|
|
|
$result = [];
|
|
|
|
|
$usedCapacity = [];
|
|
|
|
|
$assignedPlans = [];
|
|
|
|
|
$allAssigned = true;
|
|
|
|
|
|
|
|
|
|
// 遍历 items,逐个分配
|
|
|
|
|
foreach ($items as $item) {
|
|
|
|
|
// 如果该 item 已经分配,跳过
|
|
|
|
|
$alreadyAssigned = false;
|
|
|
|
|
foreach ($result as $r) {
|
|
|
|
|
if ($r['id'] == $item['id']) {
|
|
|
|
|
$alreadyAssigned = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ($alreadyAssigned) continue;
|
|
|
|
|
|
|
|
|
|
// 找可用号源
|
|
|
|
|
$assigned = false;
|
|
|
|
|
foreach ($availablePlans as $plan) {
|
|
|
|
|
$planId = $plan->id;
|
|
|
|
|
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0) - ($plan->locked_count ?? 0);
|
|
|
|
|
$used = $usedCapacity[$planId] ?? 0;
|
|
|
|
|
|
|
|
|
|
if (($remaining - $used) > 0) {
|
|
|
|
|
// 分配此号源
|
|
|
|
|
if (($remaining - $used) <= 0) continue;
|
|
|
|
|
|
|
|
|
|
// 冲突检查:不同排班且时间段重叠
|
|
|
|
|
if ($this->isTimeConflict($assignedPlans, $plan)) continue;
|
|
|
|
|
|
|
|
|
|
$result[] = [
|
|
|
|
|
'id' => $item['id'],
|
|
|
|
|
'plan_id' => $planId,
|
|
|
|
|
@ -504,20 +539,77 @@ public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appoint
|
|
|
|
|
'end_time' => $plan->end_time
|
|
|
|
|
];
|
|
|
|
|
$usedCapacity[$planId] = ($usedCapacity[$planId] ?? 0) + 1;
|
|
|
|
|
$assignedPlans[] = [
|
|
|
|
|
'resource_name' => $plan->department_resources_name,
|
|
|
|
|
'begin_time' => $plan->begin_time,
|
|
|
|
|
'end_time' => $plan->end_time
|
|
|
|
|
];
|
|
|
|
|
$assigned = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!$assigned) {
|
|
|
|
|
$allAssigned = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果所有 items 都已分配,停止遍历
|
|
|
|
|
if (count($result) >= count($items)) {
|
|
|
|
|
break;
|
|
|
|
|
if ($allAssigned) {
|
|
|
|
|
return \Yz::Return(true, '获取成功', $result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$currentDate->modify('+1 day');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return \Yz::Return(true, '获取成功', $result);
|
|
|
|
|
return \Yz::Return(true, '获取成功', []);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取指定日期的可用号源(已排序)
|
|
|
|
|
private function getAvailablePlansForDate($regnum, $entrustids, $episodeid, $appointment_type, $date, $scope, $userDeptId)
|
|
|
|
|
{
|
|
|
|
|
$s = $this->GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $date, $scope, $userDeptId);
|
|
|
|
|
if (!$s['status']) return [];
|
|
|
|
|
|
|
|
|
|
$planList = $s['data']['plan_list'] ?? [];
|
|
|
|
|
if (count($planList) == 0) return [];
|
|
|
|
|
|
|
|
|
|
$nowtime = date('Y-m-d H:i:s');
|
|
|
|
|
$availablePlans = [];
|
|
|
|
|
foreach ($planList as $plan) {
|
|
|
|
|
$planEndTime = $plan->date . ' ' . $plan->end_time;
|
|
|
|
|
if ($planEndTime > $nowtime && $plan->plan_enable) {
|
|
|
|
|
$availablePlans[] = $plan;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (count($availablePlans) == 0) return [];
|
|
|
|
|
|
|
|
|
|
usort($availablePlans, function($a, $b) {
|
|
|
|
|
$timeA = $a->date . ' ' . ($a->begin_time ?? '00:00:00');
|
|
|
|
|
$timeB = $b->date . ' ' . ($b->begin_time ?? '00:00:00');
|
|
|
|
|
return $timeA <=> $timeB;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return $availablePlans;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 冲突检查:同一排班资源允许重叠,不同排班时间不能重叠
|
|
|
|
|
private function isTimeConflict($assignedPlans, $plan)
|
|
|
|
|
{
|
|
|
|
|
foreach ($assignedPlans as $assigned) {
|
|
|
|
|
if ($assigned['resource_name'] === $plan->department_resources_name) {
|
|
|
|
|
continue; // 同排班,允许重叠
|
|
|
|
|
}
|
|
|
|
|
// 不同排班:检查时间段是否重叠
|
|
|
|
|
$aStart = $assigned['begin_time'];
|
|
|
|
|
$aEnd = $assigned['end_time'];
|
|
|
|
|
$bStart = $plan->begin_time;
|
|
|
|
|
$bEnd = $plan->end_time;
|
|
|
|
|
// [aStart, aEnd) ∩ [bStart, bEnd) ≠ ∅ → 冲突
|
|
|
|
|
if ($aStart < $bEnd && $bStart < $aEnd) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//开始预约占用名额
|
|
|
|
|
|