diff --git a/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php b/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php
index 59d9f41..615836e 100644
--- a/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php
+++ b/Laravel/app/Http/Controllers/API/Admin/YeWu/PlanListController.php
@@ -214,9 +214,10 @@ public function GetOptimalPlan()
$episodeid = request('episodeid');
$appointment_type = request('appointment_type');
$items = request('items');
+ $occupied_plan_ids = request('occupied_plan_ids', []);
$service = new PlanListService();
- return $service->GetOptimalPlan($type, $regnum, $entrustid, $episodeid, $appointment_type, $items);
+ return $service->GetOptimalPlan($type, $regnum, $entrustid, $episodeid, $appointment_type, $items, 'all', 0, $occupied_plan_ids);
}
//获取最近可用的,计划 日期
diff --git a/Laravel/app/Services/Admin/YeWu/PlanListService.php b/Laravel/app/Services/Admin/YeWu/PlanListService.php
index e1b28c2..2f3a3a8 100644
--- a/Laravel/app/Services/Admin/YeWu/PlanListService.php
+++ b/Laravel/app/Services/Admin/YeWu/PlanListService.php
@@ -425,7 +425,7 @@ public function GetEnablePlan($regnum, $entrustids, $episodeid, $appointment_typ
}
//最优时间/单天全检 分配
- public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope = 'all', $userDeptId = 0)
+ public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope = 'all', $userDeptId = 0, $occupied_plan_ids = [])
{
date_default_timezone_set('PRC');
$dateRange = config('app.globals.可用号源查询范围');
@@ -435,14 +435,14 @@ public function GetOptimalPlan($type, $regnum, $entrustids, $episodeid, $appoint
$endDate->modify('+' . $dateRange . ' day');
if ($type === 'full_day') {
- return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId);
+ return $this->doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
} else {
- return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId);
+ return $this->doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids);
}
}
// 最优时间分配:按科室分组,逐个 item 找最早可用号源,可跨天
- private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId)
+ private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [])
{
// 按科室分组
$deptGroups = $this->groupItemsByDept($items);
@@ -471,6 +471,14 @@ private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids,
$availablePlans = $this->getAvailablePlansForDate($regnum, $groupEntrustids, $episodeid, $appointment_type, $nowdate, $scope, $userDeptId);
+ // 过滤已占用的号源
+ 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);
+ }
+
if (empty($availablePlans)) {
// 当天该科室无号源,整组留到下一轮
$newRemainingGroups[$deptCode] = $group;
@@ -531,7 +539,7 @@ private function doOptimalTimeAssign($startDate, $endDate, $regnum, $entrustids,
}
// 单天全检分配:所有 item 必须在同一天完成
- private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId)
+ private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $episodeid, $appointment_type, $items, $scope, $userDeptId, $occupied_plan_ids = [])
{
// 按科室分组
$deptGroups = $this->groupItemsByDept($items);
@@ -549,6 +557,14 @@ private function doFullDayAssign($startDate, $endDate, $regnum, $entrustids, $ep
foreach ($deptGroups as $deptCode => $group) {
$availablePlans = $this->getAvailablePlansForDate($regnum, $group['entrustids'], $episodeid, $appointment_type, $nowdate, $scope, $userDeptId);
+ // 过滤已占用的号源
+ 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);
+ }
+
if (empty($availablePlans)) {
$allAssigned = false;
break;
diff --git a/YiJi-admin/index.html b/YiJi-admin/index.html
index 2d50d3a..b30ca9d 100644
--- a/YiJi-admin/index.html
+++ b/YiJi-admin/index.html
@@ -1,5 +1,5 @@
-
+
diff --git a/YiJi-admin/src/components/Yewu/YuYue202506.vue b/YiJi-admin/src/components/Yewu/YuYue202506.vue
index 2471713..0d72950 100644
--- a/YiJi-admin/src/components/Yewu/YuYue202506.vue
+++ b/YiJi-admin/src/components/Yewu/YuYue202506.vue
@@ -3,22 +3,33 @@
{{patientInfo.user_name}}({{patientInfo.user_sex_label}} {{patientInfo.age}}岁)
-
登记号:{{patientInfo.reg_num}}
+
{{patientInfo.patient_type_label}}号:{{patientInfo.patient_type == 0 ? patientInfo.episodeid?.slice(-10) : patientInfo.reg_num}}
电话:{{patientInfo.user_phone}}
病区:{{patientInfo.warddesc}}
床号:{{patientInfo.bedname}}
-
诊断:{{patientInfo.diagnosisName}}
+
诊断:{{patientInfo.diagnosisName}}
获取患者信息失败
+
+
+ 患者所有检查项目未预约至同一天,请注意是否需手动调整预约
+
+
-
-
-
-
+
+
+
+
+
共 {{entrustTableDate.length}} 项,已选 {{selectedMianListId.length}} 项
+
同检查室项目 {{sameDeptGroupCount}} 项
+
+
+ {{ scope.$index + 1 }}
{{scope.row.tishi_msg}}
正常
@@ -31,20 +42,20 @@
完成
-
-
+
+
是
否
-
+
是
否
-
+
@@ -52,24 +63,24 @@
v-if="scope.row.period_begin_time && scope.row.period_end_time ">{{scope.row.period_begin_time.substring(0, 5)}}~{{scope.row.period_end_time.substring(0, 5)}}
-
+
否
是
-
-
+
+
{{scope.row.entrust_date}} {{scope.row.entrust_time}}
-
+
-
-
+
+
{{item}}
@@ -81,18 +92,23 @@
打印申请单隐藏按钮
打印申请单
-
- 预约完成后打印申请单
-
-
- 自动选中能一起预约的检查项目
-
+
+
+ 预约完成后打印申请单
+
+
+ 自动选中能一起预约的检查项目
+
+
推荐最近时间号源
推荐同一天号源
+
+ 推荐同一时段号源
+
@@ -109,7 +125,7 @@
| {{item2}}{{item2.use_count}} |
@@ -149,6 +165,31 @@
+
+
+
+
+
+
+
最近可用的同一时间段号源数量不足,无法把当前全部检查项目预约在同一时间段,系统已经自动拆分。
+
+
+
+
+ 确定
+
+
+
+
+
+ 确定
+
+
@@ -170,6 +211,7 @@
ElMessage,
ElMessageBox
} from 'element-plus'
+ import { WarningFilled } from '@element-plus/icons-vue'
import ShenQingDan from '@/components/Yewu/PrintShenQingDan.vue'
const props = defineProps({
reg_num: {
@@ -206,6 +248,8 @@
let planTableData = ref([]);
let loading = ref(false);
let planLoading = ref(false);
+ let print_shenqingdan_button = ref(null)
+ let highlightedPlanIds = ref([])
let zhenShiList = ref([]);
let activeZhenShi = ref('');
let selectedPlanId = ref(0)
@@ -214,7 +258,6 @@
let selectedRows = ref([])
let isHandlingSelection = ref(true) //防止冒泡 死循环
let lastSelection = ref([]) //上一次操作勾选的记录 用了比对 是取消还是 勾选
- let print_shenqingdan_button = ref(null)
let auto_print = ref(['1']);
let shenqingdan_show = ref(false);
let buttonsDisabled = ref(true)
@@ -230,20 +273,40 @@
2.已预约状态,预约到同一个时段的同一个检查室的项目,系统会自动选中,更改预约或取消预约只需点击一次
3.不同状态的预约的预约项目无法一起选中`
let TanChuangMsgDialogVisible=ref(false)
+ let crossTimeDialogVisible = ref(false)
+ let crossTimeDialogHtml = ref('')
+ let resultDialogVisible = ref(false)
+ let resultDialogHtml = ref('')
const getWeekday = (date1) => {
let days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const date = new Date(date1); // 注意:格式可能因浏览器而异
const dayOfWeek = date.getDay();
return days[dayOfWeek]
}
+ const sameDeptGroupCount = computed(() => {
+ const selectedDepts = selectedRows.value
+ .map(v => v.department_resources?.department_resources_name)
+ .filter(Boolean)
+ const uniqueDepts = [...new Set(selectedDepts)]
+ if (uniqueDepts.length !== 1) return 0
+ const deptName = uniqueDepts[0]
+ return entrustTableDate.value.filter(v =>
+ v.department_resources?.department_resources_name === deptName
+ ).length
+ })
+
const canEmergency = computed(() => { //是否有紧急权限
return props.special_privileges.includes('emergency');
});
const hasDifferentBookedDates = computed(() => {
- const booked = entrustTableDate.value.filter(v => v.list_status === 1 && v.reservation_date);
- if (booked.length < 2) return false;
- const dates = new Set(booked.map(v => v.reservation_date));
- return dates.size > 1;
+ const dated = entrustTableDate.value.filter(v => {
+ if (v.list_status === 1 && v.reservation_date) return true
+ if (v.list_status === 0 && v.temp_plan_id && v.reservation_date) return true
+ return false
+ })
+ if (dated.length < 2) return false
+ const dates = new Set(dated.map(v => v.reservation_date))
+ return dates.size > 1
});
const handleSelectionChange = (selection) => {
selectedMianListId.value = []
@@ -277,6 +340,17 @@
}
} else {
selectedPlanId.value = 0;
+ // 同检查室(同一执行科室)时切换诊室
+ if (selectedRows.value.length > 0) {
+ const firstExecId = selectedRows.value[0]?.department_resources?.execute_department_id
+ const allSameExecDept = firstExecId && selectedRows.value.every(
+ v => v.department_resources?.execute_department_id === firstExecId
+ )
+ if (allSameExecDept) {
+ const firstDept = selectedRows.value[0].department_resources?.department_resources_name
+ if (firstDept) activeZhenShi.value = firstDept
+ }
+ }
}
//--------------------------------------------------------------^^^^^
@@ -343,7 +417,7 @@
}
let TanChuangMsg=ref([]);//第一次进来把所有异常提示一次
- const GetMainInfo = () => {
+ const GetMainInfo = (callback, skipRestore) => {
let tempSelected = selectedMianListId.value
entrustTableDate.value = []
loading.value = true
@@ -371,7 +445,7 @@
}
})
- if (tempSelected.length > 0) {
+ if (tempSelected.length > 0 && !skipRestore) {
tempSelected.forEach((v, i) => {
entrustTableDate.value.forEach((v2, i2) => {
if (v == v2.id) {
@@ -381,19 +455,24 @@
})
})
- } else { //进来后默认选中第一个可以勾选的
+ } else { //进来后默认选中第一个未预约的项目及同检查室项目
for (let i = 0; i < entrustTableDate.value.length; i++) {
- if (entrustTableDate.value[i].tishi_msg == '') {
+ if (entrustTableDate.value[i].tishi_msg == '' && entrustTableDate.value[i].list_status === 0) {
entrustTableRef.value.toggleRowSelection(entrustTableDate.value[i], true)
+ const dept = entrustTableDate.value[i].department_resources?.department_resources_name
+ // 勾选同检查室的其他未预约项目
+ if (dept) {
+ entrustTableDate.value.forEach(v => {
+ if (v.id !== entrustTableDate.value[i].id && v.list_status === 0 && v.tishi_msg === '' && v.department_resources?.department_resources_name === dept) {
+ entrustTableRef.value.toggleRowSelection(v, true)
+ }
+ })
+ }
if(entrustTableDate.value[i].roster_id!=null){
selectedPlanId.value=entrustTableDate.value[i].roster_id
- // startDate.value=entrustTableDate.value[i].reservation_date
- //date_list.value = getDatesAfter(entrustTableDate.value[i].reservation_date)
- activeZhenShi.value=entrustTableDate.value[i].department_resources?.department_resources_name
+ activeZhenShi.value=dept
}
-
-
- break;
+ break
}
}
}
@@ -408,6 +487,7 @@
}
// 缓存列表原始数据(深拷贝,与显示列表解耦)
cachedListData.value = JSON.parse(JSON.stringify(entrustTableDate.value))
+ if (callback) callback()
}
} else {
ElMessage.error(res.msg)
@@ -561,10 +641,12 @@
// 优先高亮已分配或已预约的号源
selectedPlanId.value = 0
- const highlightPlanId = findHighlightPlanId()
- if (highlightPlanId) {
- selectedPlanId.value = highlightPlanId
+ const highlightPlanIds = findHighlightPlanIds()
+ if (highlightPlanIds.length > 0) {
+ highlightedPlanIds.value = highlightPlanIds
+ selectedPlanId.value = highlightPlanIds[0]
} else {
+ highlightedPlanIds.value = []
// 没有匹配的,才高亮第一个可用号源
const firstAvailable = plans.find(v =>
v.department_resources_name == activeZhenShi.value &&
@@ -612,10 +694,53 @@
target.period_end_time = item.end_time
target.temp_plan_id = item.plan_id
})
+
+ // 跨时段检测
+ const roomMap = {}
+ res.data.forEach(item => {
+ const room = item.department_resources_name
+ if (!roomMap[room]) roomMap[room] = { items: [], timeSlots: new Set(), dates: new Set() }
+ roomMap[room].items.push(item)
+ roomMap[room].timeSlots.add(item.begin_time?.substring(0, 5) + '-' + item.end_time?.substring(0, 5))
+ roomMap[room].dates.add(item.date)
+ })
+ const crossParts = []
+ for (const [room, info] of Object.entries(roomMap)) {
+ if (info.timeSlots.size > 1 || info.dates.size > 1) {
+ info.items.forEach(v => {
+ const idx = entrustTableDate.value.findIndex(r => r.id === v.id)
+ crossParts.push({
+ idx: idx !== -1 ? idx + 1 : '',
+ room: v.department_resources_name,
+ date: v.date,
+ timeSlot: v.begin_time?.substring(0, 5) + '-' + v.end_time?.substring(0, 5),
+ entrust: entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
+ })
+ })
+ }
+ }
+ if (crossParts.length > 0) {
+ let crossMsg = ''
+ crossMsg += '| 序号 | 项目名称 | 检查室 | 日期 | 时间段 |
'
+ let lastSlot = ''
+ let bgColor = '#f5f5f5'
+ crossParts.sort((a, b) => a.idx - b.idx).forEach(p => {
+ if (p.timeSlot !== lastSlot) {
+ bgColor = bgColor === '#fff' ? '#f5f5f5' : '#fff'
+ lastSlot = p.timeSlot
+ }
+ crossMsg += '| ' + p.idx + ' | ' + p.entrust + ' | ' + p.room + ' | ' + p.date + ' | ' + p.timeSlot + ' |
'
+ })
+ crossMsg += '
'
+ crossTimeDialogHtml.value = crossMsg
+ crossTimeDialogVisible.value = true
+ }
+
// 更新高亮
- const newHighlightId = findHighlightPlanId()
- if (newHighlightId) {
- selectedPlanId.value = newHighlightId
+ const newHighlightIds = findHighlightPlanIds()
+ if (newHighlightIds.length > 0) {
+ highlightedPlanIds.value = newHighlightIds
+ selectedPlanId.value = newHighlightIds[0]
}
}
})
@@ -665,31 +790,35 @@
const zhenshiClick = (zhenshi) => {
activeZhenShi.value = zhenshi
selectedPlanId.value = 0
+ highlightedPlanIds.value = []
GetEnablePlanFunc()
}
- // 从已分配或已预约的行中,找到在当前排班下可高亮的号源ID
- const findHighlightPlanId = () => {
- // 优先找申请中行的临时分配号源
+ // 从已分配或已预约的行中,收集在当前排班下可高亮的号源ID列表
+ const findHighlightPlanIds = () => {
+ const ids = []
+ // 只处理当前勾选的申请中行
for (const row of entrustTableDate.value) {
+ if (!selectedMianListId.value.includes(row.id)) continue
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
+ if (plan && !ids.includes(plan.id)) ids.push(plan.id)
}
}
- // 再找已预约行的roster_id
+ // 只处理当前勾选的已预约行
for (const row of entrustTableDate.value) {
+ if (!selectedMianListId.value.includes(row.id)) continue
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
+ if (plan && !ids.includes(plan.id)) ids.push(plan.id)
}
}
- return 0
+ return ids
}
const PlanClick = (planid) => {
console.log(planid)
@@ -707,6 +836,7 @@
}
selectedPlanId.value = planid
+ highlightedPlanIds.value = [planid]
checkDaijianFuc()
// 同步更新显示列表中的排班、预约日期、预约时间
@@ -750,7 +880,7 @@
})
// 收集所有申请中行的当前信息
- const items = entrustTableDate.value
+ const items = selectedRows.value
.filter(v => v.list_status === 0)
.map(v => ({
id: v.id,
@@ -761,6 +891,11 @@
end_time: v.period_end_time || ''
}))
+ // 收集未勾选但已临时匹配号源的项目ID
+ const occupiedPlanIds = entrustTableDate.value
+ .filter(v => !selectedMianListId.value.includes(v.id) && v.list_status === 0 && v.temp_plan_id)
+ .map(v => v.temp_plan_id)
+
// 调用后端接口
GetOptimalPlan({
type: 'optimal_time',
@@ -769,6 +904,7 @@
episodeid: props.episode_id,
appointment_type: props.appointment_type,
items: items,
+ occupied_plan_ids: occupiedPlanIds,
scope: props.scope,
do_user: props.do_user
}).then(res => {
@@ -787,8 +923,67 @@
target.period_end_time = item.end_time
target.temp_plan_id = item.plan_id
})
+
+ // 跨时段检测
+ const roomMap = {}
+ res.data.forEach(item => {
+ const room = item.department_resources_name
+ if (!roomMap[room]) roomMap[room] = { items: [], timeSlots: new Set(), dates: new Set() }
+ roomMap[room].items.push(item)
+ roomMap[room].timeSlots.add(item.begin_time?.substring(0, 5) + '-' + item.end_time?.substring(0, 5))
+ roomMap[room].dates.add(item.date)
+ })
+ const crossParts = []
+ for (const [room, info] of Object.entries(roomMap)) {
+ if (info.timeSlots.size > 1 || info.dates.size > 1) {
+ info.items.forEach(v => {
+ const idx = entrustTableDate.value.findIndex(i => i.id === v.id)
+ crossParts.push({
+ idx: idx !== -1 ? idx + 1 : '',
+ room: v.department_resources_name,
+ date: v.date,
+ timeSlot: v.begin_time?.substring(0, 5) + '-' + v.end_time?.substring(0, 5),
+ entrust: entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
+ })
+ })
+ }
+ }
+ if (crossParts.length > 0) {
+ let crossMsg = ''
+ crossMsg += '| 序号 | 项目名称 | 检查室 | 日期 | 时间段 |
'
+ let lastSlot = ''
+ let bgColor = '#f5f5f5'
+ crossParts.sort((a, b) => a.idx - b.idx).forEach(p => {
+ if (p.timeSlot !== lastSlot) {
+ bgColor = bgColor === '#fff' ? '#f5f5f5' : '#fff'
+ lastSlot = p.timeSlot
+ }
+ crossMsg += '| ' + p.idx + ' | ' + p.entrust + ' | ' + p.room + ' | ' + p.date + ' | ' + p.timeSlot + ' |
'
+ })
+ crossMsg += '
'
+ crossTimeDialogHtml.value = crossMsg
+ crossTimeDialogVisible.value = true
+ }
+
+ // 未匹配检测
+ const matchedIds = new Set(res.data.map(v => v.id))
+ const unmatched = items.filter(v => !matchedIds.has(v.id))
+ if (unmatched.length > 0) {
+ let msg = '✅ 成功匹配 ' + res.data.length + ' 项:\n'
+ msg += res.data.map(v => ' ' + v.department_resources_name + ' ' + v.date + ' ' + v.begin_time?.substring(0, 5) + '-' + v.end_time?.substring(0, 5)).join('\n')
+ msg += '\n\n❌ 未匹配 ' + unmatched.length + ' 项:\n'
+ msg += unmatched.map(v => ' ' + (items.findIndex(i => i.id === v.id) + 1) + '、' + v.entrust_id + ':未找到合适号源').join('\n')
+ ElMessageBox.confirm(msg, '预约推荐结果', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', showCancelButton: false })
+ } else if (res.data.length === 0) {
+ ElMessageBox.confirm('所有项目均未匹配到合适号源,请重新选择号源', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'error', showCancelButton: false })
+ }
+
// 更新高亮
if (res.data.length > 0) {
+ // 切换诊室为第一项的排班资源
+ activeZhenShi.value = res.data[0].department_resources_name
+ // 收集所有推荐结果的plan_id用于多高亮
+ highlightedPlanIds.value = res.data.map(v => v.plan_id)
selectedPlanId.value = res.data[0].plan_id
}
} else {
@@ -818,7 +1013,7 @@
})
// 收集所有申请中行的当前信息
- const items = entrustTableDate.value
+ const items = selectedRows.value
.filter(v => v.list_status === 0)
.map(v => ({
id: v.id,
@@ -829,6 +1024,11 @@
end_time: v.period_end_time || ''
}))
+ // 收集未勾选但已临时匹配号源的项目ID
+ const occupiedPlanIds = entrustTableDate.value
+ .filter(v => !selectedMianListId.value.includes(v.id) && v.list_status === 0 && v.temp_plan_id)
+ .map(v => v.temp_plan_id)
+
// 调用后端接口
GetOptimalPlan({
type: 'full_day',
@@ -837,6 +1037,7 @@
episodeid: props.episode_id,
appointment_type: props.appointment_type,
items: items,
+ occupied_plan_ids: occupiedPlanIds,
scope: props.scope,
do_user: props.do_user
}).then(res => {
@@ -855,9 +1056,152 @@
target.period_end_time = item.end_time
target.temp_plan_id = item.plan_id
})
- // 更新高亮
+
if (res.data.length > 0) {
+ // 跨时段检测
+ const roomMap = {}
+ res.data.forEach(item => {
+ const room = item.department_resources_name
+ if (!roomMap[room]) roomMap[room] = { items: [], timeSlots: new Set(), dates: new Set() }
+ roomMap[room].items.push(item)
+ roomMap[room].timeSlots.add(item.begin_time?.substring(0, 5) + '-' + item.end_time?.substring(0, 5))
+ roomMap[room].dates.add(item.date)
+ })
+ const crossParts = []
+ for (const [room, info] of Object.entries(roomMap)) {
+ if (info.timeSlots.size > 1 || info.dates.size > 1) {
+ info.items.forEach(v => {
+ const idx = entrustTableDate.value.findIndex(i => i.id === v.id)
+ crossParts.push({
+ idx: idx !== -1 ? idx + 1 : '',
+ room: v.department_resources_name,
+ date: v.date,
+ timeSlot: v.begin_time?.substring(0, 5) + '-' + v.end_time?.substring(0, 5),
+ entrust: entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
+ })
+ })
+ }
+ }
+ if (crossParts.length > 0) {
+ let crossMsg = ''
+ crossMsg += '| 序号 | 项目名称 | 检查室 | 日期 | 时间段 |
'
+ let lastSlot = ''
+ let bgColor = '#f5f5f5'
+ crossParts.sort((a, b) => a.idx - b.idx).forEach(p => {
+ if (p.timeSlot !== lastSlot) {
+ bgColor = bgColor === '#fff' ? '#f5f5f5' : '#fff'
+ lastSlot = p.timeSlot
+ }
+ crossMsg += '| ' + p.idx + ' | ' + p.entrust + ' | ' + p.room + ' | ' + p.date + ' | ' + p.timeSlot + ' |
'
+ })
+ crossMsg += '
'
+ crossTimeDialogHtml.value = crossMsg
+ crossTimeDialogVisible.value = true
+ }
+
+ // 更新高亮
+ activeZhenShi.value = res.data[0].department_resources_name
+ highlightedPlanIds.value = res.data.map(v => v.plan_id)
selectedPlanId.value = res.data[0].plan_id
+ } else {
+ ElMessageBox.confirm('未找到任何一天可满足所有检查项目的号源', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', showCancelButton: false })
+ }
+ } else {
+ ElMessage.error(res.msg)
+ }
+ })
+ }
+ // 推荐同一时段号源
+ const sameTimeSlotClick = () => {
+ 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 = selectedRows.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 || ''
+ }))
+
+ // 收集未勾选但已临时匹配号源的项目ID
+ const occupiedPlanIds = entrustTableDate.value
+ .filter(v => !selectedMianListId.value.includes(v.id) && v.list_status === 0 && v.temp_plan_id)
+ .map(v => v.temp_plan_id)
+
+ // 调用后端接口(复用同一天号源接口)
+ GetOptimalPlan({
+ type: 'full_day',
+ regnum: props.reg_num,
+ entrustid: selectedEntrustId.value,
+ episodeid: props.episode_id,
+ appointment_type: props.appointment_type,
+ items: items,
+ occupied_plan_ids: occupiedPlanIds,
+ scope: props.scope,
+ do_user: props.do_user
+ }).then(res => {
+ planLoading.value = false
+ if (res.status) {
+ if (res.data.length > 0) {
+ // 检查同检查室是否跨时段
+ const roomMap = {}
+ res.data.forEach(item => {
+ const room = item.department_resources_name
+ if (!roomMap[room]) roomMap[room] = { timeSlots: new Set() }
+ roomMap[room].timeSlots.add(item.begin_time?.substring(0, 5) + '-' + item.end_time?.substring(0, 5))
+ })
+ let hasCrossSlot = false
+ for (const info of Object.values(roomMap)) {
+ if (info.timeSlots.size > 1) {
+ hasCrossSlot = true
+ break
+ }
+ }
+
+ if (hasCrossSlot) {
+ ElMessageBox.confirm('未找到同一时段号源,无法匹配', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', showCancelButton: false })
+ return
+ }
+
+ // 同一时段,更新显示列表
+ 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
+ })
+ // 切换诊室
+ activeZhenShi.value = res.data[0].department_resources_name
+ // 多高亮
+ highlightedPlanIds.value = res.data.map(v => v.plan_id)
+ selectedPlanId.value = res.data[0].plan_id
+ } else {
+ ElMessageBox.confirm('未找到同一时段号源,无法匹配', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', showCancelButton: false })
}
} else {
ElMessage.error(res.msg)
@@ -921,46 +1265,252 @@
})
}
- const startYuYue = (type) => {
+ const startYuYue = async (type) => {
planLoading.value = true
- PlanYuYue({
- mainlistid: selectedMianListId.value,
- planid: selectedPlanId.value,
- appointment_type: props.appointment_type,
- dotype: type, //1预约2改约,
- do_user:props.do_user,
- is_emergency:type==111?1:null
- }).then(res => {
+ // 缓存未勾选但已有临时匹配号源的项目
+ const tempPlanCache = {}
+ entrustTableDate.value.forEach(v => {
+ if (!selectedMianListId.value.includes(v.id) && v.temp_plan_id) {
+ tempPlanCache[v.id] = {
+ temp_plan_id: v.temp_plan_id,
+ department_resources_name: v.department_resources?.department_resources_name,
+ reservation_date: v.reservation_date,
+ period_begin_time: v.period_begin_time,
+ period_end_time: v.period_end_time
+ }
+ }
+ })
+ console.log('tempPlanCache 缓存:', JSON.parse(JSON.stringify(tempPlanCache)))
+
+ // 按号源分组
+ const groupMap = {}
+ let hasMissingPlan = false
+ selectedMianListId.value.forEach(id => {
+ const row = entrustTableDate.value.find(v => v.id === id)
+ const planId = row?.temp_plan_id || row?.roster_id
+ if (!planId) {
+ hasMissingPlan = true
+ return
+ }
+ if (!groupMap[planId]) groupMap[planId] = []
+ groupMap[planId].push(id)
+ })
+
+ if (hasMissingPlan) {
planLoading.value = false
- if (res.status) {
- systemConfigs.value.forEach((v,i)=>{
- if(v.label=='开启申请单pdf' && v.value==="1"){
- CreateJianChaShenQingDanPdfFunc()
+ ElMessage.error('存在未分配号源的项目,请先选择号源')
+ return
+ }
+
+ const groupKeys = Object.keys(groupMap)
+
+ // 单组:保持现有逻辑
+ if (groupKeys.length === 1) {
+ const planId = Number(groupKeys[0])
+ const ids = groupMap[planId]
+ PlanYuYue({
+ mainlistid: ids,
+ planid: planId,
+ appointment_type: props.appointment_type,
+ dotype: type,
+ do_user: props.do_user,
+ is_emergency: type == 111 ? 1 : null
+ }).then(res => {
+ planLoading.value = false
+ if (res.status) {
+ systemConfigs.value.forEach((v, i) => {
+ if (v.label == '开启申请单pdf' && v.value === "1") {
+ CreateJianChaShenQingDanPdfFunc()
+ }
+ })
+ GetMainInfo(() => {
+ // 勾选所有未预约的项目及同检查室项目
+ isHandlingSelection.value = false
+ const originalSelection = [...selectedMianListId.value]
+ const unbooked = entrustTableDate.value.filter(v => v.list_status === 0 && v.tishi_msg === '')
+ if (unbooked.length === 0) {
+ // 全部已预约,恢复之前选中的项目
+ originalSelection.forEach(id => {
+ const row = entrustTableDate.value.find(v => v.id === id)
+ if (row) entrustTableRef.value.toggleRowSelection(row, true)
+ })
+ } else {
+ entrustTableRef.value.clearSelection()
+ const deptNames = new Set(
+ unbooked.map(v => v.department_resources?.department_resources_name).filter(Boolean)
+ )
+ entrustTableDate.value.forEach(v => {
+ if (v.tishi_msg !== '') return
+ if (v.list_status === 0 || deptNames.has(v.department_resources?.department_resources_name)) {
+ entrustTableRef.value.toggleRowSelection(v, true)
+ }
+ })
}
- })
- GetMainInfo()
- if (auto_print.value.length > 0) {
- print_shenqingdan()
- }
- } else {
- ElMessageBox.confirm(
- res.msg,
- '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'error',
- showCancelButton: false
+ isHandlingSelection.value = true
+ // 恢复未勾选项目的临时匹配号源
+ entrustTableDate.value.forEach(v => {
+ if (tempPlanCache[v.id]) {
+ console.log('回填 temp_plan_id:', v.id, tempPlanCache[v.id].temp_plan_id)
+ v.temp_plan_id = tempPlanCache[v.id].temp_plan_id
+ if (!v.department_resources) v.department_resources = {}
+ v.department_resources.department_resources_name = tempPlanCache[v.id].department_resources_name
+ v.reservation_date = tempPlanCache[v.id].reservation_date
+ v.period_begin_time = tempPlanCache[v.id].period_begin_time
+ v.period_end_time = tempPlanCache[v.id].period_end_time
}
- )
- .then(() => {
-
})
- .catch(() => {
+ console.log('回填后 entrustTableDate:', JSON.parse(JSON.stringify(entrustTableDate.value.map(v => ({id: v.id, temp_plan_id: v.temp_plan_id, list_status: v.list_status})))))
+ setTimeout(() => {
+ console.log('延迟检查 temp_plan_id:', JSON.parse(JSON.stringify(entrustTableDate.value.map(v => ({id: v.id, temp_plan_id: v.temp_plan_id, list_status: v.list_status})))))
+ }, 2000)
+ // 刷新当前选中项目的号源
+ if (selectedRows.value.length > 0) {
+ const firstDept = selectedRows.value[0].department_resources?.department_resources_name
+ if (firstDept) activeZhenShi.value = firstDept
+ }
+ GetEnablePlanFunc()
+ }, true)
+ if (auto_print.value.length > 0) {
+ print_shenqingdan()
+ }
+ } else {
+ ElMessageBox.confirm(
+ res.msg,
+ '提示', {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'error',
+ showCancelButton: false
+ }
+ )
+ .then(() => {
+
+ })
+ .catch(() => {
+
+ })
+ }
+ })
+ return
+ }
+ // 多组:串行调用,汇总结果
+ const successItems = []
+ const failItems = []
+ const successEntrustIds = []
+
+ for (const planIdStr of groupKeys) {
+ const planId = Number(planIdStr)
+ const ids = groupMap[planIdStr]
+
+ try {
+ const res = await PlanYuYue({
+ mainlistid: ids,
+ planid: planId,
+ appointment_type: props.appointment_type,
+ dotype: type,
+ do_user: props.do_user,
+ is_emergency: type == 111 ? 1 : null
+ })
+ if (res.status) {
+ ids.forEach(id => {
+ const row = entrustTableDate.value.find(v => v.id === id)
+ if (row) {
+ const timeStr = (row.period_begin_time ? row.period_begin_time.substring(0, 5) : '') + '-' + (row.period_end_time ? row.period_end_time.substring(0, 5) : '')
+ successItems.push({ name: row.entrust, room: row.department_resources?.department_resources_name || '', date: row.reservation_date || '', time: timeStr })
+ successEntrustIds.push(row.entrust_id)
+ }
})
+ } else {
+ ids.forEach(id => {
+ const row = entrustTableDate.value.find(v => v.id === id)
+ if (row) failItems.push({ name: row.entrust, msg: res.msg })
+ })
+ }
+ } catch (e) {
+ ids.forEach(id => {
+ const row = entrustTableDate.value.find(v => v.id === id)
+ if (row) failItems.push({ name: row.entrust, msg: '请求异常' })
+ })
}
+ }
+
+ planLoading.value = false
+
+ // 弹窗汇总
+ // 构建结果表格
+ let html = ''
+ html += '| 序号 | 项目名称 | 检查室 | 日期 | 时间段 | 结果 |
'
+ let idx = 1
+ successItems.forEach(item => {
+ html += '| ' + (idx++) + ' | ' + item.name + ' | ' + item.room + ' | ' + item.date + ' | ' + item.time + ' | 预约成功 |
'
+ })
+ failItems.forEach(f => {
+ html += '| ' + (idx++) + ' | ' + f.name + ' | — | ' + f.msg + ' |
'
})
+ html += '
'
+ resultDialogHtml.value = html
+ resultDialogVisible.value = true
+
+ // 有成功项则刷新数据、生成PDF、自动打印
+ if (successItems.length > 0) {
+ GetMainInfo(() => {
+ // 勾选所有未预约的项目及同检查室项目
+ isHandlingSelection.value = false
+ const originalSelection = [...selectedMianListId.value]
+ const unbooked = entrustTableDate.value.filter(v => v.list_status === 0 && v.tishi_msg === '')
+ if (unbooked.length === 0) {
+ // 全部已预约,恢复之前选中的项目
+ originalSelection.forEach(id => {
+ const row = entrustTableDate.value.find(v => v.id === id)
+ if (row) entrustTableRef.value.toggleRowSelection(row, true)
+ })
+ } else {
+ entrustTableRef.value.clearSelection()
+ const deptNames = new Set(
+ unbooked.map(v => v.department_resources?.department_resources_name).filter(Boolean)
+ )
+ entrustTableDate.value.forEach(v => {
+ if (v.tishi_msg !== '') return
+ if (v.list_status === 0 || deptNames.has(v.department_resources?.department_resources_name)) {
+ entrustTableRef.value.toggleRowSelection(v, true)
+ }
+ })
+ }
+ isHandlingSelection.value = true
+ // 恢复未勾选项目的临时匹配号源
+ entrustTableDate.value.forEach(v => {
+ if (tempPlanCache[v.id]) {
+ console.log('回填 temp_plan_id:', v.id, tempPlanCache[v.id].temp_plan_id)
+ v.temp_plan_id = tempPlanCache[v.id].temp_plan_id
+ if (!v.department_resources) v.department_resources = {}
+ v.department_resources.department_resources_name = tempPlanCache[v.id].department_resources_name
+ v.reservation_date = tempPlanCache[v.id].reservation_date
+ v.period_begin_time = tempPlanCache[v.id].period_begin_time
+ v.period_end_time = tempPlanCache[v.id].period_end_time
+ }
+ })
+ console.log('回填后 entrustTableDate:', JSON.parse(JSON.stringify(entrustTableDate.value.map(v => ({id: v.id, temp_plan_id: v.temp_plan_id, list_status: v.list_status})))))
+ setTimeout(() => {
+ console.log('延迟检查 temp_plan_id:', JSON.parse(JSON.stringify(entrustTableDate.value.map(v => ({id: v.id, temp_plan_id: v.temp_plan_id, list_status: v.list_status})))))
+ }, 2000)
+ // 刷新当前选中项目的号源
+ if (selectedRows.value.length > 0) {
+ const firstDept = selectedRows.value[0].department_resources?.department_resources_name
+ if (firstDept) activeZhenShi.value = firstDept
+ }
+ GetEnablePlanFunc()
+ }, true)
+ systemConfigs.value.forEach((v, i) => {
+ if (v.label == '开启申请单pdf' && v.value === "1") {
+ CreateJianChaShenQingDanPdfFunc(successEntrustIds)
+ }
+ })
+ if (auto_print.value.length > 0) {
+ print_shenqingdan(successEntrustIds)
+ }
+ }
}
//取消预约(此界面取消预约,不验证密码)
const CancelYuYueFunc = () => {
@@ -974,6 +1524,30 @@
}
)
.then(async () => {
+ // 缓存未勾选但已有临时匹配号源的项目
+ const tempPlanCache = {}
+ entrustTableDate.value.forEach(v => {
+ if (!selectedMianListId.value.includes(v.id) && v.temp_plan_id) {
+ tempPlanCache[v.id] = {
+ temp_plan_id: v.temp_plan_id,
+ department_resources_name: v.department_resources?.department_resources_name,
+ reservation_date: v.reservation_date,
+ period_begin_time: v.period_begin_time,
+ period_end_time: v.period_end_time
+ }
+ }
+ })
+
+ // 缓存要取消的项目(用于后续推荐)
+ const cancelledItemsCache = selectedRows.value.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 || ''
+ }))
+
loading.value = true
const promises = selectedRows.value.map((v) => {
return DoctorCancelYuYue({
@@ -996,7 +1570,59 @@
await Promise.all(promises)
loading.value = false
- GetMainInfo()
+ GetMainInfo(() => {
+ // 回填未勾选项目的临时匹配号源
+ entrustTableDate.value.forEach(v => {
+ if (tempPlanCache[v.id]) {
+ v.temp_plan_id = tempPlanCache[v.id].temp_plan_id
+ if (!v.department_resources) v.department_resources = {}
+ v.department_resources.department_resources_name = tempPlanCache[v.id].department_resources_name
+ v.reservation_date = tempPlanCache[v.id].reservation_date
+ v.period_begin_time = tempPlanCache[v.id].period_begin_time
+ v.period_end_time = tempPlanCache[v.id].period_end_time
+ }
+ })
+
+ // 对已取消的项目(list_status 从 1 → 0)自动执行时间推荐
+ const cancelledItems = cancelledItemsCache
+
+ if (cancelledItems.length > 0) {
+ const occupiedPlanIds = entrustTableDate.value
+ .filter(v => !cancelledItems.find(c => c.id === v.id) && v.list_status === 0 && v.temp_plan_id)
+ .map(v => v.temp_plan_id)
+
+ GetOptimalPlan({
+ type: 'optimal_time',
+ regnum: props.reg_num,
+ entrustid: cancelledItems.map(v => v.entrust_id),
+ episodeid: props.episode_id,
+ appointment_type: props.appointment_type,
+ items: cancelledItems,
+ occupied_plan_ids: occupiedPlanIds,
+ scope: props.scope,
+ do_user: props.do_user
+ }).then(res => {
+ if (res.status && res.data.length > 0) {
+ // 更新显示列表
+ 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
+ })
+ // 切换诊室为第一项的排班资源
+ activeZhenShi.value = res.data[0].department_resources_name
+ // 多高亮
+ highlightedPlanIds.value = res.data.map(v => v.plan_id)
+ selectedPlanId.value = res.data[0].plan_id
+ }
+ })
+ }
+ }, true)
})
@@ -1018,9 +1644,10 @@
})
}
//生成pdf文件
- const CreateJianChaShenQingDanPdfFunc=()=>{
+ const CreateJianChaShenQingDanPdfFunc=(entrustIds)=>{
+ const ids = entrustIds || selectedEntrustId.value
CreateJianChaShenQingDanPdf({
- OrderNoList: selectedEntrustId.value,
+ OrderNoList: ids,
}).then(res => {
if(res.status){
@@ -1029,10 +1656,11 @@
}
//打印申请单
let shenqingdan_list = ref([])
- const print_shenqingdan = () => {
+ const print_shenqingdan = (entrustIds) => {
+ const ids = entrustIds || selectedEntrustId.value
getMainDetail({
regnum: props.reg_num,
- entrustid: selectedEntrustId.value.join(','),
+ entrustid: ids.join(','),
episodeid: props.episode_id,
appointment_type: props.appointment_type
}).then(res => {
@@ -1139,8 +1767,15 @@
\ No newline at end of file
diff --git a/YiJi-admin/src/views/YeWu/DoctorYuYue.vue b/YiJi-admin/src/views/YeWu/DoctorYuYue.vue
index b5dd251..d62791f 100644
--- a/YiJi-admin/src/views/YeWu/DoctorYuYue.vue
+++ b/YiJi-admin/src/views/YeWu/DoctorYuYue.vue
@@ -45,6 +45,8 @@
\ No newline at end of file
diff --git a/YiJi-admin/src/views/YeWu/MainList.vue b/YiJi-admin/src/views/YeWu/MainList.vue
index 6ad1577..c880ebe 100644
--- a/YiJi-admin/src/views/YeWu/MainList.vue
+++ b/YiJi-admin/src/views/YeWu/MainList.vue
@@ -3,7 +3,7 @@
-
+
@@ -910,6 +910,18 @@
display: none;
}
+ .el-dialog.is-fullscreen {
+ display: flex;
+ flex-direction: column;
+ }
+
+ .el-dialog.is-fullscreen .el-dialog__body {
+ flex: 1;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ }
+