|
|
|
|
@ -22,6 +22,7 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
|
|
|
|
|
$allDevice = [];//所有医嘱检查项目绑定的设备id
|
|
|
|
|
$commPatientType = [];//所有医嘱共同的病人类型
|
|
|
|
|
$zhanweiCount=0;//勾选的检查项目共计占多少名额
|
|
|
|
|
$shareSlotMaxSeats = 0;//共享号源项目的use_seats最大值
|
|
|
|
|
$allItemRules = [];//所有检查项目的TIME_RESTRICTION规则
|
|
|
|
|
foreach ($entrustids as $key => $entrustid) {
|
|
|
|
|
// $info = DB::table('s_list')->where(['reg_num' => $regnum, 'entrust_id' => $entrustid, 'episodeid' => $episodeid, 'is_nullify' => 0])->first();
|
|
|
|
|
@ -35,7 +36,11 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
|
|
|
|
|
$itemInfo = DB::table('s_check_item')->where(['item_name' => $info->entrust, 'status' => 1, "is_del" => 0])->get();
|
|
|
|
|
if (count($itemInfo) == 0) return \Yz::echoError1('没有找到可用的检查项目信息');
|
|
|
|
|
$itemInfo = $itemInfo[0];
|
|
|
|
|
if (!empty($itemInfo->is_share_slot)) {
|
|
|
|
|
$shareSlotMaxSeats = max($shareSlotMaxSeats, isset($itemInfo->use_seats) ? $itemInfo->use_seats : 0);
|
|
|
|
|
} else {
|
|
|
|
|
$zhanweiCount += isset($itemInfo->use_seats) ? $itemInfo->use_seats : 0;
|
|
|
|
|
}
|
|
|
|
|
$qudaos = explode(',', $itemInfo->reservation_method);
|
|
|
|
|
//只判断主渠道,如果主渠道支持,则子渠道默认也支持,即使项目没绑定子渠道
|
|
|
|
|
if (!in_array($appointment_type, $qudaos)) return \Yz::echoError1('此检查项目不支持在当前渠道预约');
|
|
|
|
|
@ -64,6 +69,12 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 共享号源项目合并计算:只取最大值
|
|
|
|
|
if ($shareSlotMaxSeats > 0) {
|
|
|
|
|
$zhanweiCount += $shareSlotMaxSeats;
|
|
|
|
|
}
|
|
|
|
|
$newSharedMax = $shareSlotMaxSeats;
|
|
|
|
|
|
|
|
|
|
$commonDevice = []; //多个检查项目共同的设备id
|
|
|
|
|
$first = true;
|
|
|
|
|
foreach ($allDevice as $set) {
|
|
|
|
|
@ -262,6 +273,30 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
|
|
|
|
|
$pl2 = [];
|
|
|
|
|
$pp = [];
|
|
|
|
|
$nowtime = date('Y-m-d H:i:s');
|
|
|
|
|
|
|
|
|
|
// 查询该患者已有共享项目在各排班下的 max
|
|
|
|
|
$existingSharedAtPlan = [];
|
|
|
|
|
if (!empty($regnum)) {
|
|
|
|
|
$existingSharedItems = DB::table('s_list')
|
|
|
|
|
->join('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
|
|
|
|
|
->where('s_list.reg_num', $regnum)
|
|
|
|
|
->where('s_list.list_status', 1)
|
|
|
|
|
->where('s_list.roster_id', '>', 0)
|
|
|
|
|
->where('s_check_item.is_share_slot', 1)
|
|
|
|
|
->select('s_list.roster_id', 's_check_item.use_seats')
|
|
|
|
|
->get();
|
|
|
|
|
foreach ($existingSharedItems as $esi) {
|
|
|
|
|
$pid = $esi->roster_id;
|
|
|
|
|
$existingSharedAtPlan[$pid] = max($existingSharedAtPlan[$pid] ?? 0, $esi->use_seats);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Log::info('[YuYueDebug] GetEnablePlan', [
|
|
|
|
|
'regnum' => $regnum,
|
|
|
|
|
'zhanweiCount' => $zhanweiCount,
|
|
|
|
|
'newSharedMax' => $newSharedMax,
|
|
|
|
|
'existingSharedAtPlan' => $existingSharedAtPlan,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
foreach ($plan as $key => $p) {
|
|
|
|
|
// //病人类型不符合的过滤掉
|
|
|
|
|
$planPatientType = explode(",", $p->patient_type);
|
|
|
|
|
@ -284,7 +319,10 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
|
|
|
|
|
|
|
|
|
|
//过期的排在后面
|
|
|
|
|
$time = $p->date . ' ' . $p->end_time;
|
|
|
|
|
if ($time > $nowtime) {
|
|
|
|
|
$remaining = ($p->count ?? 0) - ($p->used_count ?? 0);
|
|
|
|
|
$existingMax = $existingSharedAtPlan[$p->id] ?? 0;
|
|
|
|
|
$needed = $zhanweiCount - min($newSharedMax, $existingMax);
|
|
|
|
|
if ($time > $nowtime && $remaining >= $needed) {
|
|
|
|
|
$p->plan_enable=true;
|
|
|
|
|
$pl1[] = $p;
|
|
|
|
|
} else {
|
|
|
|
|
@ -434,32 +472,84 @@ public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appoint
|
|
|
|
|
$endDate = new DateTime();
|
|
|
|
|
$endDate->modify('+' . $dateRange . ' day');
|
|
|
|
|
|
|
|
|
|
// 批量查询每个检查项目的 use_seats
|
|
|
|
|
// 批量查询每个检查项目的 use_seats 和 is_share_slot
|
|
|
|
|
$entrustIds = array_column($items, 'entrust_id');
|
|
|
|
|
$useSeatsMap = [];
|
|
|
|
|
$shareSlotMap = [];
|
|
|
|
|
if (!empty($entrustIds)) {
|
|
|
|
|
$useSeatsMap = DB::table('s_list')
|
|
|
|
|
$itemData = DB::table('s_list')
|
|
|
|
|
->join('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
|
|
|
|
|
->whereIn('s_list.entrust_id', $entrustIds)
|
|
|
|
|
->pluck('s_check_item.use_seats', 's_list.entrust_id')
|
|
|
|
|
->toArray();
|
|
|
|
|
->select('s_list.entrust_id', 's_check_item.use_seats', 's_check_item.is_share_slot')
|
|
|
|
|
->get();
|
|
|
|
|
foreach ($itemData as $row) {
|
|
|
|
|
$useSeatsMap[$row->entrust_id] = $row->use_seats;
|
|
|
|
|
$shareSlotMap[$row->entrust_id] = $row->is_share_slot ?? 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach ($items as &$item) {
|
|
|
|
|
$item['use_seats'] = $useSeatsMap[$item['entrust_id']] ?? 1;
|
|
|
|
|
$item['is_share_slot'] = $shareSlotMap[$item['entrust_id']] ?? 0;
|
|
|
|
|
}
|
|
|
|
|
unset($item);
|
|
|
|
|
|
|
|
|
|
// 共享号源项目合并计算:只保留最大值,其余设为0
|
|
|
|
|
$shareSlotItems = array_filter($items, function($it) { return !empty($it['is_share_slot']); });
|
|
|
|
|
if (count($shareSlotItems) > 1) {
|
|
|
|
|
$maxSeats = 0;
|
|
|
|
|
foreach ($shareSlotItems as $it) {
|
|
|
|
|
$maxSeats = max($maxSeats, $it['use_seats']);
|
|
|
|
|
}
|
|
|
|
|
// 找到 use_seats 最高的共享项目,将 max 分配给它
|
|
|
|
|
$maxShareItemIdx = null;
|
|
|
|
|
$maxShareSeats = 0;
|
|
|
|
|
foreach ($items as $idx => $it) {
|
|
|
|
|
if (!empty($it['is_share_slot']) && $it['use_seats'] > $maxShareSeats) {
|
|
|
|
|
$maxShareSeats = $it['use_seats'];
|
|
|
|
|
$maxShareItemIdx = $idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
foreach ($items as &$it) {
|
|
|
|
|
if (!empty($it['is_share_slot'])) {
|
|
|
|
|
$it['use_seats'] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unset($it);
|
|
|
|
|
if ($maxShareItemIdx !== null) {
|
|
|
|
|
$items[$maxShareItemIdx]['use_seats'] = $maxSeats;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查询该患者已有共享项目在各排班下的 max
|
|
|
|
|
$existingSharedAtPlan = [];
|
|
|
|
|
$existingSharedItems = DB::table('s_list')
|
|
|
|
|
->join('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
|
|
|
|
|
->where('s_list.reg_num', $regnum)
|
|
|
|
|
->where('s_list.list_status', 1)
|
|
|
|
|
->where('s_list.is_nullify', 0)
|
|
|
|
|
->where('s_list.roster_id', '>', 0)
|
|
|
|
|
->where('s_check_item.is_share_slot', 1)
|
|
|
|
|
->select('s_list.roster_id', 's_check_item.use_seats')
|
|
|
|
|
->get();
|
|
|
|
|
foreach ($existingSharedItems as $esi) {
|
|
|
|
|
$pid = $esi->roster_id;
|
|
|
|
|
if (!isset($existingSharedAtPlan[$pid])) {
|
|
|
|
|
$existingSharedAtPlan[$pid] = 0;
|
|
|
|
|
}
|
|
|
|
|
$existingSharedAtPlan[$pid] = max($existingSharedAtPlan[$pid], $esi->use_seats);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($type === 'full_day') {
|
|
|
|
|
return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids, $existingSharedAtPlan);
|
|
|
|
|
} elseif ($type === 'same_day_slot') {
|
|
|
|
|
return $this->doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
return $this->doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids, $existingSharedAtPlan);
|
|
|
|
|
} else {
|
|
|
|
|
return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
|
|
|
|
|
return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids, $existingSharedAtPlan);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 最优时间分配:按科室分组,逐个 item 找最早可用号源,可跨天
|
|
|
|
|
private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [])
|
|
|
|
|
private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [], $existingSharedAtPlan = [])
|
|
|
|
|
{
|
|
|
|
|
// 按科室分组
|
|
|
|
|
$deptGroups = $this->groupItemsByDept($items);
|
|
|
|
|
@ -512,6 +602,11 @@ private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids,
|
|
|
|
|
foreach ($availablePlans as $plan) {
|
|
|
|
|
$planId = $plan->id;
|
|
|
|
|
$useSeats = $item['use_seats'] ?? 1;
|
|
|
|
|
// 共享项目号源持有者:减去已有共享项目的 max
|
|
|
|
|
if (!empty($item['is_share_slot']) && $useSeats > 0) {
|
|
|
|
|
$existingMax = $existingSharedAtPlan[$planId] ?? 0;
|
|
|
|
|
$useSeats = max(0, $useSeats - $existingMax);
|
|
|
|
|
}
|
|
|
|
|
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0);
|
|
|
|
|
$used = $usedCapacity[$planId] ?? 0;
|
|
|
|
|
|
|
|
|
|
@ -565,7 +660,7 @@ private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 单天全检分配:所有 item 必须在同一天完成
|
|
|
|
|
private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [])
|
|
|
|
|
private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [], $existingSharedAtPlan = [])
|
|
|
|
|
{
|
|
|
|
|
// 按科室分组
|
|
|
|
|
$deptGroups = $this->groupItemsByDept($items);
|
|
|
|
|
@ -604,6 +699,11 @@ private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $ep
|
|
|
|
|
foreach ($availablePlans as $plan) {
|
|
|
|
|
$planId = $plan->id;
|
|
|
|
|
$useSeats = $item['use_seats'] ?? 1;
|
|
|
|
|
// 共享项目号源持有者:减去已有共享项目的 max
|
|
|
|
|
if (!empty($item['is_share_slot']) && $useSeats > 0) {
|
|
|
|
|
$existingMax = $existingSharedAtPlan[$planId] ?? 0;
|
|
|
|
|
$useSeats = max(0, $useSeats - $existingMax);
|
|
|
|
|
}
|
|
|
|
|
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0);
|
|
|
|
|
$used = $usedCapacity[$planId] ?? 0;
|
|
|
|
|
|
|
|
|
|
@ -647,7 +747,7 @@ 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 = [], $existingSharedAtPlan = [])
|
|
|
|
|
{
|
|
|
|
|
// 按科室分组
|
|
|
|
|
$deptGroups = $this->groupItemsByDept($items);
|
|
|
|
|
@ -723,6 +823,11 @@ private function doSameDaySlotAssign($startDate, $endDate, $regnum, $entrustids,
|
|
|
|
|
foreach ($availablePlans as $plan) {
|
|
|
|
|
$planId = $plan->id;
|
|
|
|
|
$useSeats = $item['use_seats'] ?? 1;
|
|
|
|
|
// 共享项目号源持有者:减去已有共享项目的 max
|
|
|
|
|
if (!empty($item['is_share_slot']) && $useSeats > 0) {
|
|
|
|
|
$existingMax = $existingSharedAtPlan[$planId] ?? 0;
|
|
|
|
|
$useSeats = max(0, $useSeats - $existingMax);
|
|
|
|
|
}
|
|
|
|
|
$remaining = ($plan->count ?? 0) - ($plan->used_count ?? 0);
|
|
|
|
|
$used = $usedCapacity[$planId] ?? 0;
|
|
|
|
|
|
|
|
|
|
@ -872,6 +977,7 @@ public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_eme
|
|
|
|
|
|
|
|
|
|
$zhanweiCount=0;//各个检查项目需要占用检查名额的总和
|
|
|
|
|
$itemSeatsQueue = []; // 队列:按顺序存储每个项目需要的座位数 [项目ID => 座位数]
|
|
|
|
|
$itemSeatsData = []; // 原始数据:临时收集每个项目的use_seats和is_share_slot
|
|
|
|
|
$huchiList=[];//互斥item_id对应关系
|
|
|
|
|
$oldMainInfos = [];//临时存储原来的主表信息,用于改约
|
|
|
|
|
//遍历多个s_list表id,前端多选,一次预约多个检查项目
|
|
|
|
|
@ -908,9 +1014,11 @@ public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_eme
|
|
|
|
|
//判断互斥(暂时根据reg_num判断身份)
|
|
|
|
|
//查询想要预约的项目 其自身code
|
|
|
|
|
$item = DB::table('s_check_item')->where(['item_code' => $mainInfo->entrust_code, 'status' => 1, 'is_del' => 0])->first();
|
|
|
|
|
$itemSeatsQueue[$mainlistid]=$item->use_seats;
|
|
|
|
|
if (!$item) return \Yz::echoError1('此检查项目不可用');
|
|
|
|
|
$zhanweiCount+=$item->use_seats;
|
|
|
|
|
$itemSeatsData[$mainlistid] = [
|
|
|
|
|
'use_seats' => $item->use_seats,
|
|
|
|
|
'is_share_slot' => $item->is_share_slot ?? 0,
|
|
|
|
|
];
|
|
|
|
|
//医嘱开具后,预约时间需在设定的等待期之后,单位分钟
|
|
|
|
|
$entrust_time = $mainInfo->entrust_date . ' ' . $mainInfo->entrust_time; //医嘱时间
|
|
|
|
|
$date = new DateTime($entrust_time);
|
|
|
|
|
@ -1024,6 +1132,73 @@ public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_eme
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 共享号源项目合并计算:只保留最大值,其余设为0
|
|
|
|
|
$shareSlotIds = [];
|
|
|
|
|
$shareSlotMax = 0;
|
|
|
|
|
foreach ($itemSeatsData as $id => $data) {
|
|
|
|
|
if (!empty($data['is_share_slot'])) {
|
|
|
|
|
$shareSlotIds[] = $id;
|
|
|
|
|
$shareSlotMax = max($shareSlotMax, $data['use_seats']);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查询该排班下已有共享项目的 max
|
|
|
|
|
$existingSharedMax = 0;
|
|
|
|
|
$additionalNeeded = 0;
|
|
|
|
|
$regNum = $oldMainInfos[0]->reg_num ?? null;
|
|
|
|
|
if (!empty($shareSlotIds) && $regNum) {
|
|
|
|
|
$existingSharedItems = DB::table('s_list')
|
|
|
|
|
->join('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
|
|
|
|
|
->where('s_list.reg_num', $regNum)
|
|
|
|
|
->where('s_list.roster_id', $planid)
|
|
|
|
|
->where('s_list.list_status', 1)
|
|
|
|
|
->where('s_check_item.is_share_slot', 1)
|
|
|
|
|
->select('s_check_item.use_seats')
|
|
|
|
|
->get();
|
|
|
|
|
if ($existingSharedItems->isNotEmpty()) {
|
|
|
|
|
$existingSharedMax = $existingSharedItems->max('use_seats');
|
|
|
|
|
}
|
|
|
|
|
$overallMax = max($existingSharedMax, $shareSlotMax);
|
|
|
|
|
$additionalNeeded = max(0, $overallMax - $existingSharedMax);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 找到 use_seats 最高的共享项目,将 max 分配给它
|
|
|
|
|
$maxShareSlotId = null;
|
|
|
|
|
$maxShareSeats = 0;
|
|
|
|
|
foreach ($itemSeatsData as $id => $data) {
|
|
|
|
|
if (!empty($data['is_share_slot']) && $data['use_seats'] > $maxShareSeats) {
|
|
|
|
|
$maxShareSeats = $data['use_seats'];
|
|
|
|
|
$maxShareSlotId = $id;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$zhanweiCount = 0;
|
|
|
|
|
foreach ($itemSeatsData as $id => $data) {
|
|
|
|
|
if (!empty($data['is_share_slot'])) {
|
|
|
|
|
if ($id === $maxShareSlotId) {
|
|
|
|
|
$itemSeatsQueue[$id] = $additionalNeeded;
|
|
|
|
|
$zhanweiCount += $additionalNeeded;
|
|
|
|
|
} else {
|
|
|
|
|
$itemSeatsQueue[$id] = 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$itemSeatsQueue[$id] = $data['use_seats'];
|
|
|
|
|
$zhanweiCount += $data['use_seats'];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] YuYue 预约参数', [
|
|
|
|
|
'planid' => $planid,
|
|
|
|
|
'mainlistids' => $mainlistids,
|
|
|
|
|
'itemSeatsData' => $itemSeatsData,
|
|
|
|
|
'shareSlotMax' => $shareSlotMax,
|
|
|
|
|
'existingSharedMax' => $existingSharedMax,
|
|
|
|
|
'additionalNeeded' => $additionalNeeded,
|
|
|
|
|
'maxShareSlotId' => $maxShareSlotId,
|
|
|
|
|
'itemSeatsQueue' => $itemSeatsQueue,
|
|
|
|
|
'zhanweiCount' => $zhanweiCount,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
DB::beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
if ($do_type == 2) {
|
|
|
|
|
@ -1167,6 +1342,14 @@ public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_eme
|
|
|
|
|
return \Yz::echoError1('紧急预约失败:未找到匹配的预约渠道配置');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] 流分配结果', [
|
|
|
|
|
'plan_qudao_tempCount' => $plan_qudao_tempCount,
|
|
|
|
|
'weifenpeiCount' => $weifenpeiCount,
|
|
|
|
|
'itemChannelMap' => $itemChannelMap,
|
|
|
|
|
'roster_detail_counts' => array_map(function($c) { return ['id' => $c->id, 'type' => $c->appointment_type_id, 'count' => $c->count, 'used' => $c->used_count, 'locked' => $c->locked_count ?? 0]; }, $roster_detail_counts->toArray()),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// --- 3. 最终校验 ---
|
|
|
|
|
if ($weifenpeiCount > 0) {
|
|
|
|
|
// 如果不是紧急模式,或者紧急模式但没找到渠道导致还有剩余
|
|
|
|
|
@ -1286,11 +1469,27 @@ public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_eme
|
|
|
|
|
'is_emergency' => $is_emergency
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] 保存预约 detail', [
|
|
|
|
|
'id' => $id,
|
|
|
|
|
'entrust' => $mainInfo->entrust ?? 'unknown',
|
|
|
|
|
'details' => $details,
|
|
|
|
|
'roster_id' => $planInfo->id,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$u_mainList = DB::table('s_list')->where('id', $id)->update($u_data);
|
|
|
|
|
if (!$u_mainList) {
|
|
|
|
|
$list_all_success = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新后读回确认
|
|
|
|
|
$afterUpdate = DB::table('s_list')->where('id', $id)->value('appointment_use_plan_detail');
|
|
|
|
|
Log::info('[YuYueDebug] 更新后读回', [
|
|
|
|
|
'id' => $id,
|
|
|
|
|
'写入值' => json_encode($details),
|
|
|
|
|
'读回值' => $afterUpdate,
|
|
|
|
|
'affected' => $u_mainList,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$list_all_success) {
|
|
|
|
|
@ -1405,6 +1604,14 @@ public function CancelYuYue($MainListId, $reg_num,$do_user=null)
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] CancelYuYue 读取主表', [
|
|
|
|
|
'MainListId' => $MainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust ?? 'null',
|
|
|
|
|
'list_status' => $mainInfo->list_status ?? 'null',
|
|
|
|
|
'appointment_use_plan_detail' => $mainInfo->appointment_use_plan_detail ?? 'null',
|
|
|
|
|
'roster_id' => $mainInfo->roster_id ?? 'null',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if (!$mainInfo) {
|
|
|
|
|
return \Yz::echoError1('医嘱不存在');
|
|
|
|
|
}
|
|
|
|
|
@ -1415,6 +1622,12 @@ public function CancelYuYue($MainListId, $reg_num,$do_user=null)
|
|
|
|
|
|
|
|
|
|
$this->releaseSourceFromDetail($MainListId, $mainInfo);
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] CancelYuYue 释放后', [
|
|
|
|
|
'MainListId' => $MainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust,
|
|
|
|
|
'释放结果' => 'releaseSourceFromDetail 已执行',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$u_data = [
|
|
|
|
|
'list_status' => 0,
|
|
|
|
|
'reservation_date' => null,
|
|
|
|
|
@ -1465,6 +1678,135 @@ public function releaseSourceFromDetail($mainListId, $mainInfo = null)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$useDetailJson = $mainInfo->appointment_use_plan_detail;
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] releaseSourceFromDetail 入口', [
|
|
|
|
|
'mainListId' => $mainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust,
|
|
|
|
|
'useDetailJson' => $useDetailJson,
|
|
|
|
|
'reg_num' => $mainInfo->reg_num,
|
|
|
|
|
'roster_id' => $mainInfo->roster_id,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// 共享号源逻辑:取消号源持有者时差值释放
|
|
|
|
|
$shareItem = DB::table('s_check_item')
|
|
|
|
|
->where(['item_code' => $mainInfo->entrust_code, 'status' => 1, 'is_del' => 0])
|
|
|
|
|
->select('is_share_slot', 'use_seats')
|
|
|
|
|
->first();
|
|
|
|
|
$isShareSlot = $shareItem && !empty($shareItem->is_share_slot);
|
|
|
|
|
|
|
|
|
|
if ($isShareSlot && !empty($useDetailJson) && $useDetailJson !== '[]') {
|
|
|
|
|
// 该共享项目是号源持有者:查询其他同排班同资源的共享项目
|
|
|
|
|
$otherSharedItems = DB::table('s_list')
|
|
|
|
|
->join('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
|
|
|
|
|
->where('s_list.reg_num', $mainInfo->reg_num)
|
|
|
|
|
->where('s_list.roster_id', $mainInfo->roster_id)
|
|
|
|
|
->where('s_list.id', '!=', $mainListId)
|
|
|
|
|
->where('s_list.list_status', 1)
|
|
|
|
|
->where('s_check_item.is_share_slot', 1)
|
|
|
|
|
->select('s_check_item.use_seats')
|
|
|
|
|
->get();
|
|
|
|
|
|
|
|
|
|
if ($otherSharedItems->isNotEmpty()) {
|
|
|
|
|
$remainingMax = $otherSharedItems->max('use_seats');
|
|
|
|
|
if ($remainingMax > 0) {
|
|
|
|
|
// 解析当前持有量
|
|
|
|
|
$useDetails = json_decode($useDetailJson, true);
|
|
|
|
|
if (!is_array($useDetails)) {
|
|
|
|
|
return $this->releaseSourceFallback($mainInfo);
|
|
|
|
|
}
|
|
|
|
|
$currentCount = 0;
|
|
|
|
|
foreach ($useDetails as $d) {
|
|
|
|
|
$currentCount += (int)($d['count'] ?? 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] 共享持有者取消', [
|
|
|
|
|
'mainListId' => $mainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust,
|
|
|
|
|
'useDetails' => $useDetails,
|
|
|
|
|
'currentCount' => $currentCount,
|
|
|
|
|
'remainingMax' => $remainingMax,
|
|
|
|
|
'otherSharedCount' => $otherSharedItems->count(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// 只释放差值
|
|
|
|
|
$releaseCount = $currentCount - $remainingMax;
|
|
|
|
|
if ($releaseCount > 0) {
|
|
|
|
|
// 调整 detail 为只释放差值:从原始条目中按顺序扣除
|
|
|
|
|
$adjustedDetail = [];
|
|
|
|
|
$remainingToRelease = $releaseCount;
|
|
|
|
|
foreach ($useDetails as $d) {
|
|
|
|
|
$entryCount = (int)($d['count'] ?? 0);
|
|
|
|
|
$take = min($entryCount, $remainingToRelease);
|
|
|
|
|
if ($take > 0) {
|
|
|
|
|
$adjustedDetail[] = [
|
|
|
|
|
'roster_detail_count_id' => $d['roster_detail_count_id'],
|
|
|
|
|
'count' => $take
|
|
|
|
|
];
|
|
|
|
|
$remainingToRelease -= $take;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新剩余某个共享项目为新持有者
|
|
|
|
|
// 新持有者的 detail = 原始条目中未被释放的剩余部分
|
|
|
|
|
$newHolder = DB::table('s_list')
|
|
|
|
|
->join('s_check_item', 's_list.entrust', '=', 's_check_item.item_name')
|
|
|
|
|
->where('s_list.reg_num', $mainInfo->reg_num)
|
|
|
|
|
->where('s_list.roster_id', $mainInfo->roster_id)
|
|
|
|
|
->where('s_list.id', '!=', $mainListId)
|
|
|
|
|
->where('s_list.list_status', 1)
|
|
|
|
|
->where('s_check_item.is_share_slot', 1)
|
|
|
|
|
->select('s_list.id')
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if ($newHolder) {
|
|
|
|
|
// 有可转移的共享项目:只释放差值
|
|
|
|
|
$useDetailJson = json_encode($adjustedDetail);
|
|
|
|
|
|
|
|
|
|
$newHolderDetail = [];
|
|
|
|
|
$adjustmentIdx = 0;
|
|
|
|
|
foreach ($useDetails as $d) {
|
|
|
|
|
$entryCount = (int)($d['count'] ?? 0);
|
|
|
|
|
// 该条目被释放了多少
|
|
|
|
|
$releasedFromEntry = 0;
|
|
|
|
|
if ($adjustmentIdx < count($adjustedDetail) && $adjustedDetail[$adjustmentIdx]['roster_detail_count_id'] == $d['roster_detail_count_id']) {
|
|
|
|
|
$releasedFromEntry = $adjustedDetail[$adjustmentIdx]['count'];
|
|
|
|
|
$adjustmentIdx++;
|
|
|
|
|
}
|
|
|
|
|
$remainingInEntry = $entryCount - $releasedFromEntry;
|
|
|
|
|
if ($remainingInEntry > 0) {
|
|
|
|
|
$newHolderDetail[] = [
|
|
|
|
|
'roster_detail_count_id' => $d['roster_detail_count_id'],
|
|
|
|
|
'count' => $remainingInEntry
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
DB::table('s_list')
|
|
|
|
|
->where('id', $newHolder->id)
|
|
|
|
|
->update(['appointment_use_plan_detail' => json_encode($newHolderDetail)]);
|
|
|
|
|
}
|
|
|
|
|
// 没有可转移的共享项目:不修改 useDetailJson,正常释放逻辑释放全部
|
|
|
|
|
} else {
|
|
|
|
|
// currentCount <= remainingMax,按实际占用量正常释放全部
|
|
|
|
|
// 不修改 useDetailJson,让正常释放逻辑处理
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// remainingMax == 0:正常释放全部
|
|
|
|
|
}
|
|
|
|
|
// 没有其他共享项目:正常释放全部
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] 进入正常释放逻辑', [
|
|
|
|
|
'mainListId' => $mainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust,
|
|
|
|
|
'useDetailJson' => $useDetailJson,
|
|
|
|
|
'isShareSlot' => $isShareSlot ? 'true' : 'false',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if ($isShareSlot && empty($useDetailJson)) {
|
|
|
|
|
// 共享项目但不是号源持有者,不释放号源
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($useDetailJson)) {
|
|
|
|
|
$fallbackResult = $this->releaseSourceFallback($mainInfo);
|
|
|
|
|
return $fallbackResult;
|
|
|
|
|
@ -1505,6 +1847,15 @@ public function releaseSourceFromDetail($mainListId, $mainInfo = null)
|
|
|
|
|
'updated_at' => date('Y-m-d H:i:s')
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] 释放号源', [
|
|
|
|
|
'mainListId' => $mainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust,
|
|
|
|
|
'rosterDetailCountId' => $rosterDetailCountId,
|
|
|
|
|
'countToRelease' => $countToRelease,
|
|
|
|
|
'currentVersion' => $currentVersion,
|
|
|
|
|
'affected' => $affected,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
if ($affected == 0) {
|
|
|
|
|
$retryRecord = DB::table('s_source_roster_detail_count')->where(['id' => $rosterDetailCountId])->first();
|
|
|
|
|
if (!$retryRecord) {
|
|
|
|
|
@ -1543,6 +1894,12 @@ public function releaseSourceFromDetail($mainListId, $mainInfo = null)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Log::info('[YuYueDebug] releaseSourceFromDetail 返回', [
|
|
|
|
|
'mainListId' => $mainListId,
|
|
|
|
|
'entrust' => $mainInfo->entrust,
|
|
|
|
|
'allSuccess' => $allSuccess ? 'true' : 'false',
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return $allSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|