|
|
|
|
@ -8,6 +8,7 @@ use DateInterval;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
|
use DateTime;
|
|
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
use Tools;
|
|
|
|
|
|
|
|
|
|
class PlanListService
|
|
|
|
|
@ -174,36 +175,7 @@ WHERE
|
|
|
|
|
if (!$planInfo) return \Yz::echoError1('当前时段不可用');
|
|
|
|
|
if ($nowdatetime > $planInfo->date . ' ' . $planInfo->end_reservation_time) return \Yz::echoError1('已经超过预约截止时间');
|
|
|
|
|
|
|
|
|
|
//查询号源渠道是否有合并
|
|
|
|
|
$appointment_types=[$appointment_type];
|
|
|
|
|
$appointment_type_link = DB::table('s_appointment_type_ratio')->where(['department_id'=>$planInfo->department_id,'appointment_type_id' => $appointment_type])->first();
|
|
|
|
|
if (!empty($appointment_type_link->link)) {
|
|
|
|
|
$appointment_types=json_decode($appointment_type_link->link, true);
|
|
|
|
|
$appointment_types=array_merge($appointment_types, [$appointment_type]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$roster_detail_counts = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $planid])
|
|
|
|
|
->whereIn('appointment_type_id', $appointment_types)
|
|
|
|
|
->get();
|
|
|
|
|
$planZongCount=0;//合并后的各个渠道总名额
|
|
|
|
|
$planZongUsedCount=0;//合并后的各个渠道已预约的名额
|
|
|
|
|
$plan_qudao_tempCount=[];//拆分各个渠道需要占用的名额
|
|
|
|
|
$weifenpeiCount=count($mainlistids);//未分配的名额
|
|
|
|
|
foreach ($roster_detail_counts as $roster_detail_count) {
|
|
|
|
|
$planZongCount+=$roster_detail_count->count;
|
|
|
|
|
$planZongUsedCount+=$roster_detail_count->used_count;
|
|
|
|
|
$keyongCount=$roster_detail_count->count-$roster_detail_count->used_count;
|
|
|
|
|
if($weifenpeiCount-$keyongCount>=0){
|
|
|
|
|
$plan_qudao_tempCount[]=$keyongCount;
|
|
|
|
|
$weifenpeiCount-=$keyongCount;
|
|
|
|
|
}else{
|
|
|
|
|
$plan_qudao_tempCount[]=$weifenpeiCount;
|
|
|
|
|
$weifenpeiCount=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if ($planZongCount < ($planZongUsedCount + count($mainlistids))) return \Yz::echoError1('当前预约时间名额不足');
|
|
|
|
|
$zhanweiCount=0;//各个检查项目需要占用检查名额的总和
|
|
|
|
|
$huchiList=[];//互斥item_id对应关系
|
|
|
|
|
$oldMainInfos = [];//临时存储原来的主表信息,用于改约
|
|
|
|
|
//遍历多个s_list表id,前端多选,一次预约多个检查项目
|
|
|
|
|
@ -239,9 +211,9 @@ WHERE
|
|
|
|
|
|
|
|
|
|
//判断互斥(暂时根据reg_num判断身份)
|
|
|
|
|
//查询想要预约的项目 其自身code
|
|
|
|
|
$item = DB::table('s_check_item')->where(['item_name' => $mainInfo->entrust, 'status' => 1, 'is_del' => 0])->first();
|
|
|
|
|
$item = DB::table('s_check_item')->where(['item_code' => $mainInfo->entrust_code, 'status' => 1, 'is_del' => 0])->first();
|
|
|
|
|
if (!$item) return \Yz::echoError1('此检查项目不可用');
|
|
|
|
|
|
|
|
|
|
$zhanweiCount+=$item->use_seats;
|
|
|
|
|
//医嘱开具后,预约时间需在设定的等待期之后,单位分钟
|
|
|
|
|
$entrust_time = $mainInfo->entrust_date . ' ' . $mainInfo->entrust_time; //医嘱时间
|
|
|
|
|
$date = new DateTime($entrust_time);
|
|
|
|
|
@ -303,6 +275,41 @@ WHERE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//查询号源渠道是否有合并
|
|
|
|
|
$appointment_types=[$appointment_type];
|
|
|
|
|
$appointment_type_link = DB::table('s_appointment_type_ratio')->where(['department_id'=>$planInfo->department_id,'appointment_type_id' => $appointment_type])->first();
|
|
|
|
|
if (!empty($appointment_type_link->link)) {
|
|
|
|
|
$appointment_types=json_decode($appointment_type_link->link, true);
|
|
|
|
|
$appointment_types=array_merge($appointment_types, [$appointment_type]);
|
|
|
|
|
sort($appointment_types);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$roster_detail_counts = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $planid])
|
|
|
|
|
->whereIn('appointment_type_id', $appointment_types)
|
|
|
|
|
->orderBy('appointment_type_id','asc')
|
|
|
|
|
->get();
|
|
|
|
|
$planZongCount=0;//合并后的各个渠道总名额
|
|
|
|
|
$planZongUsedCount=0;//合并后的各个渠道已预约的名额
|
|
|
|
|
$plan_qudao_tempCount=[];//拆分各个渠道需要占用的名额
|
|
|
|
|
$weifenpeiCount=$zhanweiCount;//未分配的名额
|
|
|
|
|
foreach ($roster_detail_counts as $roster_detail_count) {
|
|
|
|
|
$planZongCount+=$roster_detail_count->count;
|
|
|
|
|
$planZongUsedCount+=$roster_detail_count->used_count;
|
|
|
|
|
$keyongCount=$roster_detail_count->count-$roster_detail_count->used_count;
|
|
|
|
|
if($weifenpeiCount-$keyongCount>=0){
|
|
|
|
|
$plan_qudao_tempCount[]=$keyongCount;
|
|
|
|
|
$weifenpeiCount-=$keyongCount;
|
|
|
|
|
}else{
|
|
|
|
|
$plan_qudao_tempCount[]=$weifenpeiCount;
|
|
|
|
|
$weifenpeiCount=0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if ($planZongCount < ($planZongUsedCount +$zhanweiCount)) return \Yz::echoError1('当前预约时间名额不足');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//判断某人这些待预约项目里,是否存在互斥
|
|
|
|
|
$userGroup=[];
|
|
|
|
|
foreach ($oldMainInfos as $key1 => $value1) {
|
|
|
|
|
@ -372,16 +379,17 @@ WHERE
|
|
|
|
|
];
|
|
|
|
|
$list_all_success =true;
|
|
|
|
|
$offset = 0;
|
|
|
|
|
|
|
|
|
|
foreach($plan_qudao_tempCount as $key=>$length){
|
|
|
|
|
if($length==0) continue;
|
|
|
|
|
$u_data['appointment_type_id']= $appointment_types[$key];
|
|
|
|
|
|
|
|
|
|
// 获取当前批次的记录 ID
|
|
|
|
|
$currentBatchIds = array_slice($mainlistids, $offset, $length);
|
|
|
|
|
$currentBatchIds = array_slice($mainlistids, $offset, $length);//这块逻辑得优化,之前是1个项目占位1个,现在有可能1个项目占位多个
|
|
|
|
|
|
|
|
|
|
foreach ($currentBatchIds as $id) {
|
|
|
|
|
// 为当前记录生成唯一的排队号
|
|
|
|
|
$xuhao = $this->generateQueueNumber($planInfo->id);
|
|
|
|
|
|
|
|
|
|
// 更新当前记录的数据(包括 xuhao)
|
|
|
|
|
$u_data['xuhao'] = $xuhao;
|
|
|
|
|
$u_mainList = DB::table('s_list')
|
|
|
|
|
@ -503,48 +511,175 @@ WHERE
|
|
|
|
|
date_default_timezone_set('PRC');
|
|
|
|
|
$nowdatetime = date("Y-m-d H:i:s");
|
|
|
|
|
|
|
|
|
|
$mainInfo = DB::table('s_list')->where(['id' => $MainListId, 'reg_num' => $reg_num])->first();
|
|
|
|
|
if (!$mainInfo) return \Yz::echoError1('医嘱不存在');
|
|
|
|
|
//判断状态
|
|
|
|
|
if ($mainInfo->list_status <> 1) return \Yz::echoError1('该记录无法取消,当前状态:' . $mainInfo->list_status);
|
|
|
|
|
// 开启数据库事务
|
|
|
|
|
DB::beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
// 1. 查询并锁定主预约记录(防并发)
|
|
|
|
|
$mainInfo = DB::table('s_list')
|
|
|
|
|
->where(['id' => $MainListId, 'reg_num' => $reg_num])
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$mainInfo) {
|
|
|
|
|
return \Yz::echoError1('医嘱不存在');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 检查当前状态是否允许取消(仅状态为1可取消)
|
|
|
|
|
if ($mainInfo->list_status != 1) {
|
|
|
|
|
return \Yz::echoError1('该记录无法取消,当前状态:' . $mainInfo->list_status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 获取检查项目信息(判断是否可用)
|
|
|
|
|
$item = DB::table('s_check_item')
|
|
|
|
|
->where(['item_code' => $mainInfo->entrust_code, 'status' => 1, 'is_del' => 0])
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$item) {
|
|
|
|
|
return \Yz::echoError1('此检查项目不可用');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$zhanweiCount = (int)$item->use_seats; // 该预约占用的号源数量
|
|
|
|
|
$rosterId = $mainInfo->roster_id; // 排班详情ID
|
|
|
|
|
|
|
|
|
|
if ($zhanweiCount <= 0) {
|
|
|
|
|
$zhanweiCount = 1; // 防止配置错误,默认至少占1个号源
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 查询排班详情并加锁(确保号源操作安全)
|
|
|
|
|
$planInfo = DB::table('s_source_roster_detail')
|
|
|
|
|
->where(['id' => $rosterId])
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$planInfo) {
|
|
|
|
|
return \Yz::echoError1('号源排班信息不存在');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 获取当前预约类型的合并渠道配置
|
|
|
|
|
$appointment_type_link = DB::table('s_appointment_type_ratio')
|
|
|
|
|
->where([
|
|
|
|
|
'department_id' => $planInfo->department_id,
|
|
|
|
|
'appointment_type_id' => $mainInfo->appointment_type_id
|
|
|
|
|
])
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
// 构建可用的预约类型列表(包含自身 + 合并渠道)
|
|
|
|
|
$appointment_types = [$mainInfo->appointment_type_id];
|
|
|
|
|
if (!empty($appointment_type_link->link)) {
|
|
|
|
|
$linkTypes = json_decode($appointment_type_link->link, true);
|
|
|
|
|
if (is_array($linkTypes)) {
|
|
|
|
|
$appointment_types = array_merge($appointment_types, $linkTypes);
|
|
|
|
|
}
|
|
|
|
|
$appointment_types = array_unique($appointment_types); // 去重
|
|
|
|
|
sort($appointment_types);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. 获取当前渠道已使用的号源数量
|
|
|
|
|
$currentCountRecord = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $mainInfo->appointment_type_id])
|
|
|
|
|
->lockForUpdate() // 加锁
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$currentCountRecord) {
|
|
|
|
|
return \Yz::echoError1('当前渠道号源计数记录不存在');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$usedCurrent = (int)$currentCountRecord->used_count;
|
|
|
|
|
|
|
|
|
|
// 7. 开始释放号源:优先从当前渠道释放,不足则从合并渠道扣除
|
|
|
|
|
$remainingRelease = $zhanweiCount; // 还需释放的数量
|
|
|
|
|
|
|
|
|
|
// 先从当前预约类型渠道释放
|
|
|
|
|
if ($usedCurrent >= $remainingRelease) {
|
|
|
|
|
// 当前渠道足够释放
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $mainInfo->appointment_type_id])
|
|
|
|
|
->decrement('used_count', $remainingRelease);
|
|
|
|
|
$remainingRelease = 0;
|
|
|
|
|
} else {
|
|
|
|
|
// 当前渠道不够,全部释放当前渠道
|
|
|
|
|
$releasedFromCurrent = $usedCurrent;
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $mainInfo->appointment_type_id])
|
|
|
|
|
->update(['used_count' => 0]);
|
|
|
|
|
$remainingRelease -= $releasedFromCurrent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果还有剩余要释放的号源,从合并渠道中扣除
|
|
|
|
|
if ($remainingRelease > 0) {
|
|
|
|
|
foreach ($appointment_types as $typeId) {
|
|
|
|
|
// 跳过当前已处理的渠道
|
|
|
|
|
if ($typeId == $mainInfo->appointment_type_id) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$mergeCountRecord = DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $typeId])
|
|
|
|
|
->lockForUpdate()
|
|
|
|
|
->first();
|
|
|
|
|
|
|
|
|
|
if (!$mergeCountRecord || $mergeCountRecord->used_count <= 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$deduct = min($mergeCountRecord->used_count, $remainingRelease);
|
|
|
|
|
DB::table('s_source_roster_detail_count')
|
|
|
|
|
->where(['roster_detail_id' => $rosterId, 'appointment_type_id' => $typeId])
|
|
|
|
|
->decrement('used_count', $deduct);
|
|
|
|
|
|
|
|
|
|
$remainingRelease -= $deduct;
|
|
|
|
|
|
|
|
|
|
if ($remainingRelease <= 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果最终仍无法完全释放所需号源数量,说明数据异常(理论上不应发生)
|
|
|
|
|
if ($remainingRelease > 0) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return \Yz::echoError1('号源释放失败:合并渠道号源不足,无法完成释放');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 8. 更新主表状态为“已取消”(0)
|
|
|
|
|
$u_data = [
|
|
|
|
|
'list_status' => 0,
|
|
|
|
|
'reservation_date' => null,
|
|
|
|
|
'reservation_time' => null,
|
|
|
|
|
'reservation_sources' => null,
|
|
|
|
|
'services_group' => null,
|
|
|
|
|
'roster_id' => null,
|
|
|
|
|
'xuhao' => null,
|
|
|
|
|
'department_id' => null,
|
|
|
|
|
'appointment_type_id' => null,
|
|
|
|
|
'canel_time' => $nowdatetime,
|
|
|
|
|
'list_status' => 0,
|
|
|
|
|
'reservation_date' => null,
|
|
|
|
|
'reservation_time' => null,
|
|
|
|
|
'reservation_sources' => null,
|
|
|
|
|
'services_group' => null,
|
|
|
|
|
'roster_id' => null,
|
|
|
|
|
'xuhao' => null,
|
|
|
|
|
'department_id' => null,
|
|
|
|
|
'appointment_type_id' => null,
|
|
|
|
|
'canel_time' => $nowdatetime,
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$u_mainList = DB::table('s_list')->where(['id' => $MainListId])->update($u_data);
|
|
|
|
|
|
|
|
|
|
// 9. 写入操作日志
|
|
|
|
|
$i_log = DB::table('s_list_log')->insert([
|
|
|
|
|
'list_id' => $mainInfo->id,
|
|
|
|
|
'reg_num' => $mainInfo->reg_num,
|
|
|
|
|
'old_status' => $mainInfo->list_status,
|
|
|
|
|
'new_status' => 0,
|
|
|
|
|
'create_user' => null,
|
|
|
|
|
'note' => '取消预约',
|
|
|
|
|
'data' => json_encode($u_data)
|
|
|
|
|
'list_id' => $mainInfo->id,
|
|
|
|
|
'reg_num' => $mainInfo->reg_num,
|
|
|
|
|
'old_status' => $mainInfo->list_status,
|
|
|
|
|
'new_status' => 0,
|
|
|
|
|
'create_user' => null,
|
|
|
|
|
'note' => '取消预约',
|
|
|
|
|
'data' => json_encode($u_data, JSON_UNESCAPED_UNICODE),
|
|
|
|
|
'created_at' => $nowdatetime,
|
|
|
|
|
]);
|
|
|
|
|
$u_count = DB::table('s_source_roster_detail_count')->where(['roster_detail_id' => $mainInfo->roster_id, 'appointment_type_id' => $mainInfo->appointment_type_id])->decrement('used_count');
|
|
|
|
|
if ($u_mainList && $u_count) {
|
|
|
|
|
DB::commit();
|
|
|
|
|
return \Yz::Return(true, '取消成功', []);
|
|
|
|
|
} else {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return \Yz::echoError1('取消失败');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 10. 提交事务
|
|
|
|
|
DB::commit();
|
|
|
|
|
|
|
|
|
|
return \Yz::Return(true, '取消成功', []);
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
DB::rollBack();
|
|
|
|
|
return \Yz::echoError1('取消异常');
|
|
|
|
|
// 记录错误日志(建议使用 Laravel 日志系统)
|
|
|
|
|
Log::error("取消预约失败 - ID: {$MainListId}, reg_num: {$reg_num}, 错误: " . $e->getMessage());
|
|
|
|
|
return \Yz::echoError1('取消失败:系统异常,请稍后重试');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
//短信提醒
|
|
|
|
|
public function SendMsg($infos,$dotype=1)
|
|
|
|
|
|