自动匹配

main
鹿和sa0ChunLuyu 2 weeks ago
parent 4b7ec9e0c5
commit 3d22681335

@ -200,8 +200,43 @@ public function GetEnablePlan()
$episodeid = request('episodeid');
$appointment_type = request('appointment_type'); //预约类型
$appointment_date = request('date'); //预约日期
$scope = request('scope', 'all');
$userDeptId = 0;
if ($scope === 'department') {
$userid = request('do_user');
if ($userid) {
$userInfo = DB::table('users')->where(['id' => $userid])->first();
$userDeptId = $userInfo->department_id ?? 0;
}
}
$service = new PlanListService();
return $service->GetEnablePlan($regnum, $entrustid, $episodeid, $appointment_type, $appointment_date, $scope, $userDeptId);
}
//最优时间/单天全检 分配
public function GetOptimalPlan()
{
$type = request('type'); // optimal_time | full_day
$regnum = request('regnum');
$entrustid = request('entrustid');
$episodeid = request('episodeid');
$appointment_type = request('appointment_type');
$items = request('items');
$scope = request('scope', 'all');
$userDeptId = 0;
if ($scope === 'department') {
$userid = request('do_user');
if ($userid) {
$userInfo = DB::table('users')->where(['id' => $userid])->first();
$userDeptId = $userInfo->department_id ?? 0;
}
}
$service = new PlanListService();
return $service->GetEnablePlan($regnum, $entrustid, $episodeid, $appointment_type, $appointment_date);
return $service->GetOptimalPlan($type, $regnum, $entrustid, $episodeid, $appointment_type, $items, $scope, $userDeptId);
}
//获取最近可用的,计划 日期

@ -145,13 +145,16 @@ public function GetList(Request $request)
})
->pluck('department_number');
//工作台科室:合并关联科室的 department_number
//工作台科室:合并关联科室及子科室的 department_number
if ($department->is_workbench == 1) {
$linkedIds = json_decode($department->linked_departments, true);
if (!empty($linkedIds) && is_array($linkedIds)) {
$linkedDeptNumbers = DB::table('s_department')
->whereIn('id', $linkedIds)
->where('is_del', 0)
->where(function($q) use ($linkedIds) {
$q->whereIn('id', $linkedIds)
->orWhereIn('pid', $linkedIds);
})
->pluck('department_number');
$deptNumbers = $deptNumbers->merge($linkedDeptNumbers);
}

@ -14,7 +14,7 @@
class PlanListService
{
public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $appointment_date)
public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $appointment_date, $scope = 'all', $userDeptId = 0)
{
date_default_timezone_set('PRC');
@ -93,6 +93,41 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
}
}
// scope=department 时,使用用户科室过滤号源(含工作台+子科室)
$deptIds = [];
$useScopeDept = false;
if ($scope === 'department' && $userDeptId > 0) {
$useScopeDept = true;
$userDept = DB::table('s_department')->where(['id' => $userDeptId, 'is_del' => 0])->first();
if ($userDept) {
// 当前科室 + 子科室
$deptIds = DB::table('s_department')
->where('is_del', 0)
->where(function($q) use ($userDeptId) {
$q->where('id', $userDeptId)
->orWhere('pid', $userDeptId);
})
->pluck('id')
->toArray();
// 工作台科室:合并关联科室及子科室
if ($userDept->is_workbench == 1) {
$linkedIds = json_decode($userDept->linked_departments, true);
if (!empty($linkedIds) && is_array($linkedIds)) {
$linkedDeptIds = DB::table('s_department')
->where('is_del', 0)
->where(function($q) use ($linkedIds) {
$q->whereIn('id', $linkedIds)
->orWhereIn('pid', $linkedIds);
})
->pluck('id')
->toArray();
$deptIds = array_unique(array_merge($deptIds, $linkedDeptIds));
}
}
}
}
if(count($commonDevice)==0) return \Yz::echoError1("无可用号源");
$placeholders = implode(',', array_fill(0, count($commonDevice), '?'));
$appointment_types_placeholders = implode(',', array_fill(0, count($appointment_types), '?'));
@ -109,7 +144,14 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
if ($isDeviceMode) {
//设备模式:不限制科室,只按单渠道查号源,渠道合路后置处理
$canshu = array_merge($commonDevice, $appointment_date_arr, [$appointment_type]);
if ($useScopeDept && !empty($deptIds)) {
$deptPlaceholders = implode(',', array_fill(0, count($deptIds), '?'));
$canshu = array_merge($commonDevice, $appointment_date_arr, $deptIds, [$appointment_type]);
$deptCondition = "AND a.department_id IN ($deptPlaceholders)";
} else {
$canshu = array_merge($commonDevice, $appointment_date_arr, [$appointment_type]);
$deptCondition = '';
}
$plan = DB::select("SELECT
a.*,
dd.devices,
@ -136,6 +178,7 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
) AS dd ON a.id = dd.roster_detail_id
WHERE
a.date IN ($appointment_dates_placeholders)
$deptCondition
AND a.STATUS = 1
AND a.is_del = 0
AND b.is_del = 0
@ -149,7 +192,14 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
$plan = $this->mergeChannelsPerDepartment($plan, $appointment_type);
} else {
//科室模式:原有逻辑
$canshu = array_merge($commonDevice, [$department_id->id], $appointment_date_arr, $appointment_types);
if ($useScopeDept) {
$deptPlaceholders = implode(',', array_fill(0, count($deptIds), '?'));
$canshu = array_merge($commonDevice, $deptIds, $appointment_date_arr, $appointment_types);
$deptCondition = "a.department_id IN ($deptPlaceholders)";
} else {
$canshu = array_merge($commonDevice, [$department_id->id], $appointment_date_arr, $appointment_types);
$deptCondition = "a.department_id = ?";
}
$plan = DB::select("SELECT
a.*,
dd.devices,
@ -175,7 +225,7 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
d.roster_detail_id
) AS dd ON a.id = dd.roster_detail_id
WHERE
a.department_id = ?
$deptCondition
AND a.date IN ($appointment_dates_placeholders)
AND a.STATUS = 1
AND a.is_del = 0
@ -372,6 +422,104 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
]);
}
//最优时间/单天全检 分配
public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope = 'all', $userDeptId = 0)
{
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');
$currentDate = clone $startDate;
while ($currentDate <= $endDate) {
$nowdate = $currentDate->format('Y-m-d');
// 获取当前日期的可用号源
$s = $this->GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_type, $nowdate, $scope, $userDeptId);
if (!$s['status']) {
$currentDate->modify('+1 day');
continue;
}
$planList = $s['data']['plan_list'] ?? [];
if (count($planList) == 0) {
$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;
}
}
if (count($availablePlans) == 0) {
$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;
});
// 遍历 items逐个分配
foreach ($items as $item) {
// 如果该 item 已经分配,跳过
$alreadyAssigned = false;
foreach ($result as $r) {
if ($r['id'] == $item['id']) {
$alreadyAssigned = true;
break;
}
}
if ($alreadyAssigned) continue;
// 找可用号源
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) {
// 分配此号源
$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;
break;
}
}
}
// 如果所有 items 都已分配,停止遍历
if (count($result) >= count($items)) {
break;
}
$currentDate->modify('+1 day');
}
return \Yz::Return(true, '获取成功', $result);
}
//开始预约占用名额
public function YuYue($planid, $appointment_type, $mainlistids, $do_type,$is_emergency=0,$do_user=null)
{

@ -151,6 +151,7 @@
Route::post('admin/GetConfigInfo','App\Http\Controllers\API\Admin\ConfigController@GetConfigInfo2'); //获取配置信息
Route::post('admin/getMainDetail','App\Http\Controllers\API\Admin\YeWu\WorkMainController@getMainDetail');//获取主表信息
Route::post('admin/GetEnablePlan','App\Http\Controllers\API\Admin\YeWu\PlanListController@GetEnablePlan');//获取可用的计划,用于计划占用
Route::post('admin/GetOptimalPlan','App\Http\Controllers\API\Admin\YeWu\PlanListController@GetOptimalPlan');//最优时间/单天全检 分配
Route::post('admin/PlanYuYue','App\Http\Controllers\API\Admin\YeWu\PlanListController@YuYue');//开始预约
Route::post('admin/CheckEntrstItemGroup','App\Http\Controllers\API\Admin\YeWu\WorkMainController@CheckEntrstItemGroup');//批量检查医嘱检查项目是否可以同时预约
Route::post('admin/CheckIsDaiJian','App\Http\Controllers\API\Admin\YeWu\WorkMainController@CheckIsDaiJian');//检查当前时段是否有存在已经预约的待检查项目

@ -469,6 +469,13 @@ export const GetEnablePlan = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'admin/GetEnablePlan', data: data })
}
//获取某日可用号源
//最优时间/单天全检 分配
// type: optimal_time | full_day
// items: 所有申请中行的当前排班信息
export const GetOptimalPlan = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'admin/GetOptimalPlan', data: data })
}
//获取某日可用号源
export const PlanYuYue = (data = {}) => {
return axios({ url: import.meta.env.VITE_APP_API + 'admin/PlanYuYue', data: data })
}

@ -84,8 +84,8 @@
<el-checkbox-group v-model="auto_print" style="margin-left: 12px;">
<el-checkbox label="1">预约完成后打印申请单</el-checkbox>
</el-checkbox-group>
<el-button class="do_button" type="primary" style="margin-left: 20px;" :disabled="buttonsDisabled">最优时间</el-button>
<el-button class="do_button" type="primary" :disabled="buttonsDisabled">单天全检</el-button>
<el-button class="do_button" type="primary" style="margin-left: 20px;" @click="optimalTimeClick"></el-button>
<el-button class="do_button" type="primary" @click="">单天全检</el-button>
</div>
<div>
<el-date-picker v-model="startDate" type="date" placeholder="跳转日期" @change="DatePickerChange()" />
@ -157,7 +157,7 @@
CheckIsDaiJian,
PlanYuYue,
CheckEntrstItemGroup2,
DoctorCancelYuYue,GetConfigInfo2,CreateJianChaShenQingDanPdf
DoctorCancelYuYue,GetConfigInfo2,CreateJianChaShenQingDanPdf,GetOptimalPlan
} from '@/api/api.js'
import {
ElMessage,
@ -187,6 +187,10 @@
special_privileges:{
type: Array,
default: () => []
},
scope: {
type: String,
default: 'all'
}
})
let entrustTableRef = ref(null)
@ -210,6 +214,10 @@
let handleType = ref('add');
let startDate = ref('');
let systemConfigs=ref([]);//
let cachedListData = ref([]) // GetMainInfo
let cachedPlans = ref([]) // GetEnablePlanFunc
let zhanWeiCount = ref(0) //
let hasAutoAssignedFirstPlan = ref(false) //
let TanChuangMsgDialogVisible=ref(false)
const getWeekday = (date1) => {
let days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
@ -383,6 +391,8 @@
}
}
//
cachedListData.value = JSON.parse(JSON.stringify(entrustTableDate.value))
}
} else {
ElMessage.error(res.msg)
@ -463,15 +473,20 @@
entrustid: selectedEntrustId.value,
episodeid: props.episode_id,
appointment_type: props.appointment_type,
date: date_list.value
date: date_list.value,
scope: props.scope,
do_user: props.do_user
}).then(res => {
planLoading.value = false
planTableData.value = []
zhenShiList.value=[]
if (res.status) {
let plans = res.data.plan_list
let zhanWeiCount=res.data.zhanWeiCount
let zwCount=res.data.zhanWeiCount
let is_emergency=res.data.is_emergency
// PlanClick使
cachedPlans.value = plans
zhanWeiCount.value = zwCount
if (plans.length > 0) {
if (activeZhenShi.value == '') activeZhenShi.value = plans[0].department_resources_name
@ -506,7 +521,7 @@
);
let plan_enable = false
if (matchingPlan) {
if (matchingPlan.count - matchingPlan.used_count >= zhanWeiCount && matchingPlan.plan_enable===true) {
if (matchingPlan.count - matchingPlan.used_count >= zwCount && matchingPlan.plan_enable===true) {
plan_enable = true
}
if(is_emergency===true && matchingPlan.plan_enable===true && canEmergency.value==true){
@ -529,15 +544,67 @@
planTableData.value.push(row);
});
// plan
//
selectedPlanId.value = 0
const firstAvailable = plans.find(v =>
v.department_resources_name == activeZhenShi.value &&
(v.count - v.used_count) >= zhanWeiCount &&
v.plan_enable === true
);
if (firstAvailable) {
selectedPlanId.value = firstAvailable.id
const highlightPlanId = findHighlightPlanId()
if (highlightPlanId) {
selectedPlanId.value = highlightPlanId
} else {
//
const firstAvailable = plans.find(v =>
v.department_resources_name == activeZhenShi.value &&
(v.count - v.used_count) >= zwCount &&
v.plan_enable === true
);
if (firstAvailable) {
selectedPlanId.value = firstAvailable.id
}
}
//
if (!hasAutoAssignedFirstPlan.value) {
hasAutoAssignedFirstPlan.value = true
const unbookedRows = entrustTableDate.value.filter(v => v.list_status === 0)
if (unbookedRows.length > 0) {
const items = unbookedRows.map(v => ({
id: v.id,
entrust_id: v.entrust_id,
department_resources_name: v.department_resources?.department_resources_name || '',
date: v.reservation_date || '',
begin_time: v.period_begin_time || '',
end_time: v.period_end_time || ''
}))
GetOptimalPlan({
type: 'optimal_time',
regnum: props.reg_num,
entrustid: selectedEntrustId.value,
episodeid: props.episode_id,
appointment_type: props.appointment_type,
items: items,
scope: props.scope,
do_user: props.do_user
}).then(res => {
if (res.status) {
res.data.forEach(item => {
const target = entrustTableDate.value.find(v => v.id === item.id)
if (!target) return
if (!target.department_resources) {
target.department_resources = {}
}
target.department_resources.department_resources_name = item.department_resources_name
target.reservation_date = item.date
target.period_begin_time = item.begin_time
target.period_end_time = item.end_time
target.temp_plan_id = item.plan_id
})
//
const newHighlightId = findHighlightPlanId()
if (newHighlightId) {
selectedPlanId.value = newHighlightId
}
}
})
}
}
}
@ -585,13 +652,134 @@
selectedPlanId.value = 0
GetEnablePlanFunc()
}
// ID
const findHighlightPlanId = () => {
//
for (const row of entrustTableDate.value) {
if (row.list_status === 0 && row.temp_plan_id) {
const plan = cachedPlans.value.find(v =>
v.id === row.temp_plan_id &&
v.department_resources_name === activeZhenShi.value
)
if (plan) return plan.id
}
}
// roster_id
for (const row of entrustTableDate.value) {
if (row.list_status === 1 && row.roster_id) {
const plan = cachedPlans.value.find(v =>
v.id === row.roster_id &&
v.department_resources_name === activeZhenShi.value
)
if (plan) return plan.id
}
}
return 0
}
const PlanClick = (planid) => {
console.log(planid)
if (planid != undefined) {
selectedPlanId.value = planid
checkDaijianFuc()
if (planid == undefined) return
//
const plan = cachedPlans.value.find(v => v.id === planid)
if (!plan) return
//
const remaining = plan.count - plan.used_count
if (remaining < zhanWeiCount.value) {
ElMessage.warning(`剩余号源不足,当前仅剩 ${remaining} 个号位,所选项目需 ${zhanWeiCount.value} 个号位`)
return
}
selectedPlanId.value = planid
checkDaijianFuc()
//
selectedRows.value.forEach(row => {
const target = entrustTableDate.value.find(v => v.id === row.id)
if (!target) return
//
if (!target.department_resources) {
target.department_resources = {}
}
target.department_resources.department_resources_name = plan.department_resources_name
//
target.reservation_date = plan.date
//
target.period_begin_time = plan.begin_time
target.period_end_time = plan.end_time
// ID
target.temp_plan_id = planid
})
}
//
const optimalTimeClick = () => {
if (selectedEntrustId.value.length === 0) {
ElMessage.error("请选择检查项目")
return
}
planLoading.value = true
//
selectedRows.value.forEach(row => {
const cachedRow = cachedListData.value.find(v => v.id === row.id)
if (!cachedRow) return
const target = entrustTableDate.value.find(v => v.id === row.id)
if (!target) return
target.department_resources = cachedRow.department_resources
target.reservation_date = cachedRow.reservation_date
target.period_begin_time = cachedRow.period_begin_time
target.period_end_time = cachedRow.period_end_time
target.temp_plan_id = undefined
})
//
const items = entrustTableDate.value
.filter(v => v.list_status === 0)
.map(v => ({
id: v.id,
entrust_id: v.entrust_id,
department_resources_name: v.department_resources?.department_resources_name || '',
date: v.reservation_date || '',
begin_time: v.period_begin_time || '',
end_time: v.period_end_time || ''
}))
//
GetOptimalPlan({
type: 'optimal_time',
regnum: props.reg_num,
entrustid: selectedEntrustId.value,
episodeid: props.episode_id,
appointment_type: props.appointment_type,
items: items,
scope: props.scope,
do_user: props.do_user
}).then(res => {
planLoading.value = false
if (res.status) {
//
res.data.forEach(item => {
const target = entrustTableDate.value.find(v => v.id === item.id)
if (!target) return
if (!target.department_resources) {
target.department_resources = {}
}
target.department_resources.department_resources_name = item.department_resources_name
target.reservation_date = item.date
target.period_begin_time = item.begin_time
target.period_end_time = item.end_time
target.temp_plan_id = item.plan_id
})
//
if (res.data.length > 0) {
selectedPlanId.value = res.data[0].plan_id
}
} else {
ElMessage.error(res.msg)
}
})
}
const checkDaijianFuc = () => {
planLoading.value = true

@ -4,7 +4,7 @@
<iframe id="bdIframe" :src="selectedUrl" class="iframe" :key="YuYueKey" scrolling="auto"></iframe>
</el-dialog>
<el-dialog v-model="YuYueVueDialogVisible" width="100%" @close="closeYuYueDialog()">
<YuYue202506 :reg_num="tableSelected[0].reg_num" :entrust_ids="entrust_ids" :key="YuYueKey" :episode_id="tableSelected[0].episodeid" appointment_type="4" :dotype="do_type" :do_user="loginUserinfo.id" :special_privileges="loginUserinfo.special_privileges"></YuYue202506>
<YuYue202506 :reg_num="tableSelected[0].reg_num" :entrust_ids="entrust_ids" :key="YuYueKey" :episode_id="tableSelected[0].episodeid" appointment_type="4" :dotype="do_type" :do_user="loginUserinfo.id" :special_privileges="loginUserinfo.special_privileges" :scope="'department'"></YuYue202506>
</el-dialog>
<div class="head">
<el-row>

Loading…
Cancel
Save