|
|
<template>
|
|
|
<div class="YuYue202506">
|
|
|
|
|
|
<div class="patientInfo" v-if="patientInfo">
|
|
|
<div class="item"><span class="name">{{patientInfo.user_name}}</span>({{patientInfo.user_sex_label}} {{patientInfo.age}}岁)</div>
|
|
|
<div class="item">{{patientInfo.patient_type_label}}号:<span class="value">{{patientInfo.patient_type == 0 ? patientInfo.episodeid?.slice(-10) : patientInfo.reg_num}} </span></div>
|
|
|
<div class="item">电话:<span class="value">{{patientInfo.user_phone}}</span></div>
|
|
|
<div class="item" v-if="patientInfo.warddesc">病区:<span class="value">{{patientInfo.warddesc}}</span></div>
|
|
|
<div class="item" v-if="patientInfo.bedname">床号:<span class="value">{{patientInfo.bedname}}</span></div>
|
|
|
<div class="item" v-if="patientInfo.diagnosisName">诊断:<span class="value">{{patientInfo.diagnosisName}}</span></div>
|
|
|
</div>
|
|
|
<div v-else>
|
|
|
获取患者信息失败
|
|
|
</div>
|
|
|
<el-alert v-if="hasDifferentBookedDates" type="danger" :closable="false" show-icon style="margin-bottom: 8px;">
|
|
|
<template #title>
|
|
|
<span style="font-weight: 700; color: #f56c6c;">患者所有检查项目未预约至同一天,请注意是否需手动调整预约</span>
|
|
|
</template>
|
|
|
</el-alert>
|
|
|
<div class="entrustList">
|
|
|
<el-table :data="entrustTableDate" style="width: 100%;" row-key="id" v-loading="loading"
|
|
|
ref="entrustTableRef" :row-class-name="setRowClassName" @selection-change="handleSelectionChange">
|
|
|
<el-table-column type="selection" width="36" :selectable="selectable" />
|
|
|
<el-table-column prop="tishi_msg" width="200">
|
|
|
<template #header>
|
|
|
<div>
|
|
|
<div>共 {{entrustTableDate.length}} 项,已选 {{selectedMianListId.length}} 项</div>
|
|
|
<div v-if="sameDeptGroupCount > 0" style="font-size: 12px; color: #909399;">同检查室项目 {{sameDeptGroupCount}} 项</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<template #default="scope">
|
|
|
<span style="margin-right: 4px; color: #999;">{{ scope.$index + 1 }}</span>
|
|
|
<span v-if="scope.row.tishi_msg!=''" class="errMsg">{{scope.row.tishi_msg}}</span>
|
|
|
<span v-else>正常</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="list_status" label="预约状态" width="80">
|
|
|
<template #default="scope">
|
|
|
<el-tag v-if="scope.row.list_status===0" class="ml-2" type="info">未预约</el-tag>
|
|
|
<el-tag v-if="scope.row.list_status===1" class="ml-2" type="success">已预约</el-tag>
|
|
|
<el-tag v-if="scope.row.list_status===2" class="ml-2">登记</el-tag>
|
|
|
<el-tag v-if="scope.row.list_status===3" class="ml-2" type="warning">完成</el-tag>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="entrust" label="项目" show-overflow-tooltip />
|
|
|
<el-table-column prop="is_pay" label="是否交费" width="60" align="center">
|
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.is_pay==1">是</span>
|
|
|
<span v-if="scope.row.is_pay==0">否</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="his_is_emergency" label="是否加急" width="60" align="center">
|
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.his_is_emergency==1" style="color: orangered;">是</span>
|
|
|
<span v-if="scope.row.his_is_emergency==0">否</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="department_resources.department_resources_name" label="排班" width="220" />
|
|
|
<el-table-column prop="reservation_date" label="预约日期" width="120" />
|
|
|
<el-table-column prop="check_begin_time" label="预约时间" width="120">
|
|
|
<template #default="scope">
|
|
|
<span
|
|
|
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)}}</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="limosis" label="是否空腹" width="60" align="center">
|
|
|
<template #default="scope">
|
|
|
<span v-if="scope.row.limosis==0">否</span>
|
|
|
<span v-else>是</span>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="reservation_department" label="申请科室" width="150" />
|
|
|
<el-table-column prop="" label="医嘱时间" width="200">
|
|
|
<template #default="scope">
|
|
|
{{scope.row.entrust_date}} {{scope.row.entrust_time}}
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column prop="docotr" label="申请医生" width="80" />
|
|
|
</el-table>
|
|
|
</div>
|
|
|
<div class="planInfo">
|
|
|
<div style="display: flex;justify-content: space-between; align-items: center; margin-top: 8px;margin-bottom: 8px;">
|
|
|
<div style="display: flex; align-items: center;">
|
|
|
<div v-for="(item ,index) in zhenShiList" :key="index"
|
|
|
:class="{'ZhenShiButton zhenshiButton_active': activeZhenShi === item,'ZhenShiButton': activeZhenShi !== item}"
|
|
|
@click="zhenshiClick(item)">{{item}}</div>
|
|
|
<div class="shuxian"></div>
|
|
|
<el-button v-if="canEmergency" class="do_button" type="danger" @click="YuYueButtonClick(111)">加急预约</el-button>
|
|
|
<el-button class="do_button" type="success" @click="YuYueButtonClick(1)">预约</el-button>
|
|
|
<el-button class="do_button" type="warning" @click="YuYueButtonClick(2)">更改预约时间</el-button>
|
|
|
<el-button class="do_button" type="danger" @click="CancelYuYueFunc()">取消预约</el-button>
|
|
|
<el-button style="display: none;" ref="print_shenqingdan_button"
|
|
|
v-print="'#shenqingdan'">打印申请单隐藏按钮</el-button>
|
|
|
<el-button @click="print_shenqingdan()">打印申请单</el-button>
|
|
|
<div style="display: flex; flex-direction: column; margin-left: 12px;">
|
|
|
<el-checkbox-group v-model="auto_print">
|
|
|
<el-checkbox label="1">预约完成后打印申请单</el-checkbox>
|
|
|
</el-checkbox-group>
|
|
|
<el-tooltip placement="top" :content="autoMatchTip" popper-class="tip-pre-line">
|
|
|
<el-checkbox v-model="autoMatchGroup">自动选中能一起预约的检查项目</el-checkbox>
|
|
|
</el-tooltip>
|
|
|
</div>
|
|
|
<el-tooltip placement="top" content="点击此按钮,系统会推荐最近能用的时间段号源,多个检查项目可能会跨天跨时间段" popper-class="tip-pre-line">
|
|
|
<el-button class="do_button_recommend" type="primary" style="margin-left: 20px; width: 120px;" @click="optimalTimeClick">推荐最近时间号源</el-button>
|
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="点击此按钮,系统会推荐最近的能在同一天完成检查的号源" popper-class="tip-pre-line">
|
|
|
<el-button class="do_button_recommend" type="primary" style="width: 120px;" @click="fullDayClick">推荐同一天号源</el-button>
|
|
|
</el-tooltip>
|
|
|
<el-tooltip placement="top" content="点击此按钮,系统会推荐最近的能在同一天同一时间段完成检查的号源" popper-class="tip-pre-line">
|
|
|
<el-button class="do_button_recommend" type="primary" @click="sameTimeSlotClick">推荐同一天同一时间段号源</el-button>
|
|
|
</el-tooltip>
|
|
|
</div>
|
|
|
<div>
|
|
|
<el-date-picker v-model="startDate" type="date" placeholder="跳转日期" @change="DatePickerChange()" />
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
<div v-loading="planLoading" style="border: 1px solid #efefef;">
|
|
|
<table class="planTable">
|
|
|
<tr style="background-color: #f1f1f1;" v-if="selectedRows.length>0">
|
|
|
<td style="width: 120px;"></td>
|
|
|
<td style="font-weight: 700;" v-for="(item,index) in date_list">{{item.substring(5, 10)}}
|
|
|
{{getWeekday(item)}}
|
|
|
</td>
|
|
|
</tr>
|
|
|
<tr v-for="(item,index) in planTableData" :key="index" class="table_plan_row" v-if="date_list.length>0 && planTableData.length>0">
|
|
|
<td v-for="(item2,index2) in item" :key="index2" :class="{
|
|
|
'planActive': (highlightedPlanIds.includes(item2.id) && item2.id !==0 && item2.id),
|
|
|
'plandisable': !item2.enable && index2 !=='time_range'
|
|
|
}" @click="PlanClick(item2.id)"><span
|
|
|
v-if="index2=='time_range'">{{item2}}</span><span>{{item2.use_count}}</span></td>
|
|
|
</tr>
|
|
|
|
|
|
</table>
|
|
|
<div v-if="selectedRows.length==0">
|
|
|
<el-empty description="请选择项目" />
|
|
|
</div>
|
|
|
<div v-if="selectedRows.length>0 && planTableData.length==0" style="background-color: #fff;">
|
|
|
<el-empty description="暂无号源" />
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
<div id="shenqingdan" v-if="shenqingdan_show" style="position: relative;">
|
|
|
<div v-for="(item,index) in shenqingdan_list" :key="index">
|
|
|
<ShenQingDan :printInfo="item.maininfo"></ShenQingDan>
|
|
|
</div>
|
|
|
</div>
|
|
|
<el-dialog
|
|
|
v-model="TanChuangMsgDialogVisible"
|
|
|
title="提示"
|
|
|
width="500"
|
|
|
>
|
|
|
<el-table :data="TanChuangMsg" style="width: 100%;" row-key="id">
|
|
|
<el-table-column prop="item_name" label="项目名称" />
|
|
|
<el-table-column prop="msg" label="异常提示" />
|
|
|
</el-table>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
<el-button type="primary" @click="TanChuangMsgDialogVisible = false">
|
|
|
确定
|
|
|
</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
<el-dialog v-model="crossTimeDialogVisible" title="提示" width="800">
|
|
|
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
|
|
<el-icon class="el-icon-warning" style="color: #e6a23c; font-size: 24px; flex-shrink: 0; margin-top: 2px;">
|
|
|
<WarningFilled />
|
|
|
</el-icon>
|
|
|
<div>
|
|
|
<p style="margin: 0 0 12px 0; font-weight: 700;">最近可用的同一时间段号源数量不足,无法把当前全部检查项目预约在同一时间段,系统已经自动拆分。</p>
|
|
|
<div v-html="crossTimeDialogHtml"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
<el-button type="primary" @click="crossTimeDialogVisible = false">确定</el-button>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
<el-dialog v-model="resultDialogVisible" title="预约结果" width="800">
|
|
|
<div style="display: flex; align-items: flex-start; gap: 12px;">
|
|
|
<el-icon style="color: #e6a23c; font-size: 24px; flex-shrink: 0; margin-top: 2px;">
|
|
|
<WarningFilled />
|
|
|
</el-icon>
|
|
|
<div v-html="resultDialogHtml"></div>
|
|
|
</div>
|
|
|
<template #footer>
|
|
|
<el-button type="primary" @click="resultDialogVisible = false">确定</el-button>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
import {
|
|
|
ref,
|
|
|
onMounted,
|
|
|
watch,computed
|
|
|
} from 'vue'
|
|
|
import {
|
|
|
getMainDetail,
|
|
|
GetEnablePlan,
|
|
|
CheckIsDaiJian,
|
|
|
PlanYuYue,
|
|
|
CheckEntrstItemGroup2,
|
|
|
DoctorCancelYuYue,GetConfigInfo2,CreateJianChaShenQingDanPdf,GetOptimalPlan
|
|
|
} from '@/api/api.js'
|
|
|
import {
|
|
|
ElMessage,
|
|
|
ElMessageBox
|
|
|
} from 'element-plus'
|
|
|
import { WarningFilled } from '@element-plus/icons-vue'
|
|
|
import ShenQingDan from '@/components/Yewu/PrintShenQingDan.vue'
|
|
|
const props = defineProps({
|
|
|
reg_num: {
|
|
|
type: String
|
|
|
},
|
|
|
entrust_ids: {
|
|
|
type: String
|
|
|
},
|
|
|
episode_id: {
|
|
|
type: String
|
|
|
},
|
|
|
appointment_type: {
|
|
|
type: [String, Number]
|
|
|
},
|
|
|
dotype: {
|
|
|
type: Number
|
|
|
},
|
|
|
do_user: {
|
|
|
default:'',
|
|
|
type: [String, Number]
|
|
|
},
|
|
|
special_privileges:{
|
|
|
type: Array,
|
|
|
default: () => []
|
|
|
},
|
|
|
scope: {
|
|
|
type: String,
|
|
|
default: 'all'
|
|
|
}
|
|
|
})
|
|
|
let entrustTableRef = ref(null)
|
|
|
let patientInfo = ref(null)
|
|
|
let entrustTableDate = ref([]);
|
|
|
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)
|
|
|
let selectedMianListId = ref([]) //勾选选中的医嘱对应的数据库id
|
|
|
let selectedEntrustId = ref([]) //勾选选中的医嘱对应的entrust_id
|
|
|
let selectedRows = ref([])
|
|
|
let isHandlingSelection = ref(true) //防止冒泡 死循环
|
|
|
let lastSelection = ref([]) //上一次操作勾选的记录 用了比对 是取消还是 勾选
|
|
|
let auto_print = ref(['1']);
|
|
|
let shenqingdan_show = ref(false);
|
|
|
let buttonsDisabled = ref(true)
|
|
|
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 autoMatchGroup = ref(true) // 自动选中能一起预约的检查项目
|
|
|
const autoMatchTip = `1.未预约状态,如果多个检查项目能在同一个检查室进行检查,系统会自动选中能一起预约的项目,只需要点击一次预约按钮即可完成预约
|
|
|
2.已预约状态,预约到同一个时段的同一个检查室的项目,系统会自动选中,更改预约或取消预约只需点击一次
|
|
|
3.不同状态的预约的预约项目无法一起选中`
|
|
|
let TanChuangMsgDialogVisible=ref(false)
|
|
|
let crossTimeDialogVisible = ref(false)
|
|
|
let crossTimeDialogHtml = ref('')
|
|
|
let cachedCrossDialogData = ref(null) // 缓存跨时段 dialog 数据:{ html, idx }
|
|
|
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 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 = []
|
|
|
selectedEntrustId.value = []
|
|
|
zhenShiList.value = []
|
|
|
planTableData.value = []
|
|
|
activeZhenShi.value = ''
|
|
|
|
|
|
selectedRows.value = selection;
|
|
|
console.log('11111',selectedRows.value)
|
|
|
selectedRows.value.forEach((v, i) => {
|
|
|
selectedMianListId.value.push(v.id)
|
|
|
selectedEntrustId.value.push(v.entrust_id)
|
|
|
})
|
|
|
|
|
|
//遍历已经勾选的项目 如果号源id都相同则 获取可以选定的号源id.------------vvvv
|
|
|
const allPlanIdsSame = selectedRows.value.every(
|
|
|
(v) => v.roster_id === selectedRows.value[0]?.roster_id
|
|
|
);
|
|
|
if (allPlanIdsSame) {
|
|
|
selectedPlanId.value = selectedRows.value[0]?.roster_id;
|
|
|
if(selectedPlanId.value!==0 && selectedPlanId.value){
|
|
|
|
|
|
startDate.value=selectedRows.value[0]?.reservation_date
|
|
|
if(checkDateDifference15Day(getTodayDate(),selectedRows.value[0]?.reservation_date) && !!selectedRows.value[0]?.reservation_date){
|
|
|
date_list.value=getDatesAfter(selectedRows.value[0]?.reservation_date)
|
|
|
}else{
|
|
|
date_list.value=getDatesAfter(getTodayDate())
|
|
|
}
|
|
|
activeZhenShi.value=selectedRows.value[0]?.department_resources?.department_resources_name
|
|
|
}
|
|
|
} 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
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
//--------------------------------------------------------------^^^^^
|
|
|
|
|
|
lastSelection.value.forEach(lastRow => {
|
|
|
if (!selectedRows.value.find(s => s === lastRow)) {
|
|
|
handleType.value = 'cancel'
|
|
|
}
|
|
|
});
|
|
|
if(selectedRows.value.length==0){//如果全部取消了,则恢复状态
|
|
|
handleType.value = 'add'
|
|
|
lastSelection.value=[]
|
|
|
}
|
|
|
|
|
|
console.log(handleType.value)
|
|
|
if (selectedEntrustId.value.length > 0 && isHandlingSelection.value) {
|
|
|
if (handleType.value === 'add' && selectedRows.value[0].list_status==0) {
|
|
|
if (autoMatchGroup.value) {
|
|
|
FindAllMatchItem();
|
|
|
} else {
|
|
|
GetEnablePlanFunc();
|
|
|
}
|
|
|
} else {
|
|
|
GetEnablePlanFunc();
|
|
|
}
|
|
|
}
|
|
|
// 检查缓存中是否有跨时段 dialog 需要弹出
|
|
|
if (cachedCrossDialogData.value) {
|
|
|
const currentIdx = entrustTableDate.value.findIndex(
|
|
|
r => selectedMianListId.value.includes(r.id)
|
|
|
) + 1
|
|
|
if (currentIdx === cachedCrossDialogData.value.idx) {
|
|
|
crossTimeDialogHtml.value = cachedCrossDialogData.value.html
|
|
|
crossTimeDialogVisible.value = true
|
|
|
cachedCrossDialogData.value = null
|
|
|
}
|
|
|
}
|
|
|
checkSameSourceRoom()
|
|
|
}
|
|
|
const checkSameSourceRoom = () => {
|
|
|
if (selectedRows.value.length === 0) {
|
|
|
buttonsDisabled.value = true
|
|
|
return
|
|
|
}
|
|
|
const firstExecId = selectedRows.value[0]?.department_resources?.execute_department_id
|
|
|
if (firstExecId === undefined || firstExecId === null) {
|
|
|
buttonsDisabled.value = true
|
|
|
return
|
|
|
}
|
|
|
const allSame = selectedRows.value.every(
|
|
|
(v) => v.department_resources?.execute_department_id === firstExecId
|
|
|
)
|
|
|
buttonsDisabled.value = !allSame
|
|
|
}
|
|
|
const isSelected = (row) => {
|
|
|
return selectedRows.value.findIndex(item => item.id === row.id) > -1;
|
|
|
}
|
|
|
const setRowClassName = ({
|
|
|
row,
|
|
|
rowIndex
|
|
|
}) => {
|
|
|
|
|
|
if (row.tishi_msg != "") {
|
|
|
return 'disabled-row';
|
|
|
}
|
|
|
if (isSelected(row)) {
|
|
|
return 'selected-row';
|
|
|
}
|
|
|
}
|
|
|
const selectable = (row, index) => {
|
|
|
if (row.tishi_msg != "") {
|
|
|
return false;
|
|
|
} else {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
let TanChuangMsg=ref([]);//第一次进来把所有异常提示一次
|
|
|
const GetMainInfo = (callback, skipRestore) => {
|
|
|
let tempSelected = selectedMianListId.value
|
|
|
entrustTableDate.value = []
|
|
|
loading.value = true
|
|
|
getMainDetail({
|
|
|
regnum: props.reg_num,
|
|
|
entrustid: props.entrust_ids,
|
|
|
episodeid: props.episode_id,
|
|
|
appointment_type: props.appointment_type
|
|
|
}).then(res => {
|
|
|
loading.value = false
|
|
|
if (res.status) {
|
|
|
if (res.data.info.length > 0) {
|
|
|
let info = res.data.info
|
|
|
patientInfo.value = info[0].maininfo
|
|
|
info.forEach((v, i) => {
|
|
|
let item_entrust_info = v.maininfo
|
|
|
item_entrust_info.tishi_msg = v.msg
|
|
|
item_entrust_info.limosis = v.iteminfo[0]?.limosis
|
|
|
entrustTableDate.value.push(item_entrust_info)
|
|
|
if(v.msg!='' && v.msg!=null){
|
|
|
TanChuangMsg.value.push({
|
|
|
msg:v.msg,
|
|
|
item_name:v.iteminfo[0]?.item_name
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
|
|
|
if (tempSelected.length > 0 && !skipRestore) {
|
|
|
tempSelected.forEach((v, i) => {
|
|
|
entrustTableDate.value.forEach((v2, i2) => {
|
|
|
if (v == v2.id) {
|
|
|
entrustTableRef.value.toggleRowSelection(entrustTableDate
|
|
|
.value[i2], true)
|
|
|
}
|
|
|
})
|
|
|
|
|
|
})
|
|
|
} else { //进来后默认选中第一个未预约的项目及同检查室项目
|
|
|
for (let i = 0; i < entrustTableDate.value.length; i++) {
|
|
|
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
|
|
|
activeZhenShi.value=dept
|
|
|
}
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(onMountedStatus.value){//如果是第一次进入,弹窗提示异常项目的状态
|
|
|
onMountedStatus.value=false;
|
|
|
if(TanChuangMsg.value.length>0){
|
|
|
console.log('22222222222222',TanChuangMsg.value)
|
|
|
TanChuangMsgDialogVisible.value=true;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
// 缓存列表原始数据(深拷贝,与显示列表解耦)
|
|
|
cachedListData.value = JSON.parse(JSON.stringify(entrustTableDate.value))
|
|
|
if (callback) callback()
|
|
|
}
|
|
|
} else {
|
|
|
ElMessage.error(res.msg)
|
|
|
}
|
|
|
|
|
|
})
|
|
|
}
|
|
|
|
|
|
const FindAllMatchItem = () => {
|
|
|
|
|
|
let list = []
|
|
|
//selectedRows.value.reverse();
|
|
|
let length=selectedRows.value.length
|
|
|
if (selectedRows.value[length-1].list_status != 0) return false //如果勾选的不是申请中的医嘱则不进行匹配
|
|
|
entrustTableDate.value.forEach((v, i) => {
|
|
|
if (v.list_status == 0 && v.tishi_msg == "") {
|
|
|
if (v.id == selectedRows.value[length-1].id) {
|
|
|
list.push({
|
|
|
name: v.entrust,
|
|
|
rowid: i,
|
|
|
first: 1
|
|
|
})
|
|
|
} else {
|
|
|
list.push({
|
|
|
name: v.entrust,
|
|
|
rowid: i,
|
|
|
first: 0
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
|
|
|
if (list.length >= 2) {
|
|
|
loading.value = true
|
|
|
CheckEntrstItemGroup2({
|
|
|
items: list
|
|
|
}).then(res => {
|
|
|
loading.value = false
|
|
|
if (res.status) {
|
|
|
list.forEach((v, i) => {
|
|
|
isHandlingSelection.value = false
|
|
|
entrustTableRef.value.toggleRowSelection(entrustTableDate.value[v.rowid],
|
|
|
false)
|
|
|
})
|
|
|
let rowids = res.data.rowids
|
|
|
// autoSeleted(d)
|
|
|
rowids.forEach((v, i) => {
|
|
|
isHandlingSelection.value = false
|
|
|
entrustTableRef.value.toggleRowSelection(entrustTableDate.value[v], true)
|
|
|
|
|
|
})
|
|
|
lastSelection.value = selectedRows.value
|
|
|
GetEnablePlanFunc()
|
|
|
|
|
|
} else {
|
|
|
ElMessage.error(res.msg)
|
|
|
}
|
|
|
isHandlingSelection.value = true
|
|
|
|
|
|
})
|
|
|
} else {
|
|
|
lastSelection.value = selectedRows.value
|
|
|
GetEnablePlanFunc()
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
let date_list = ref([]);
|
|
|
|
|
|
const GetEnablePlanFunc = () => {
|
|
|
if( selectedEntrustId.value.length==0){
|
|
|
ElMessage.error("请选择检查项目")
|
|
|
return false;
|
|
|
}
|
|
|
planLoading.value = true
|
|
|
GetEnablePlan({
|
|
|
regnum: props.reg_num,
|
|
|
entrustid: selectedEntrustId.value,
|
|
|
episodeid: props.episode_id,
|
|
|
appointment_type: props.appointment_type,
|
|
|
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 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
|
|
|
const timeSlotsSet = new Set();
|
|
|
const zhenshiSet = new Set();
|
|
|
plans.forEach(v => {
|
|
|
if (v.department_resources_name == activeZhenShi.value) {
|
|
|
const timeRange =
|
|
|
`${v.begin_time.substring(0,5)}-${v.end_time.substring(0,5)}`;
|
|
|
timeSlotsSet.add(timeRange);
|
|
|
}
|
|
|
zhenshiSet.add(v.department_resources_name)
|
|
|
});
|
|
|
zhenShiList.value = zhenshiSet
|
|
|
|
|
|
const timeSlots = Array.from(timeSlotsSet).sort(); // 排序可选
|
|
|
|
|
|
// Step 2: 构建表格数据
|
|
|
|
|
|
|
|
|
timeSlots.forEach(timeRange => {
|
|
|
const row = {
|
|
|
time_range: timeRange
|
|
|
};
|
|
|
|
|
|
date_list.value.forEach(date => {
|
|
|
const matchingPlan = plans.find(
|
|
|
v =>
|
|
|
`${v.begin_time.substring(0,5)}-${v.end_time.substring(0,5)}` ===
|
|
|
timeRange && v.date === date && v
|
|
|
.department_resources_name == activeZhenShi.value
|
|
|
);
|
|
|
let plan_enable = false
|
|
|
if (matchingPlan) {
|
|
|
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){
|
|
|
plan_enable = true
|
|
|
}
|
|
|
row[date] = {
|
|
|
use_count: `${matchingPlan.used_count}/${matchingPlan.count}`,
|
|
|
id: matchingPlan.id,
|
|
|
enable: plan_enable
|
|
|
};
|
|
|
} else {
|
|
|
row[date] = {
|
|
|
use_count: "0/0",
|
|
|
id: null,
|
|
|
enable: plan_enable
|
|
|
};
|
|
|
}
|
|
|
});
|
|
|
|
|
|
planTableData.value.push(row);
|
|
|
});
|
|
|
|
|
|
// 优先高亮已分配或已预约的号源
|
|
|
selectedPlanId.value = 0
|
|
|
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 &&
|
|
|
(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 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 = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
|
|
|
crossMsg += '<tr style="background:#f5f5f5;"><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">序号</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">项目名称</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">检查室</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">日期</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">时间段</td></tr>'
|
|
|
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 += '<tr style="background:' + bgColor + ';"><td style="padding:4px 8px;border:1px solid #ddd;">' + p.idx + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.entrust + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.room + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.timeSlot + '</td></tr>'
|
|
|
})
|
|
|
crossMsg += '</table>'
|
|
|
// 首次自动推荐:比对序号,不一致则缓存
|
|
|
const minIdx = Math.min(...crossParts.map(p => p.idx))
|
|
|
const selectedIdx = entrustTableDate.value.findIndex(
|
|
|
r => selectedMianListId.value.includes(r.id)
|
|
|
) + 1
|
|
|
if (selectedIdx === minIdx) {
|
|
|
crossTimeDialogHtml.value = crossMsg
|
|
|
crossTimeDialogVisible.value = true
|
|
|
} else {
|
|
|
cachedCrossDialogData.value = { html: crossMsg, idx: minIdx }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 更新高亮
|
|
|
const newHighlightIds = findHighlightPlanIds()
|
|
|
if (newHighlightIds.length > 0) {
|
|
|
highlightedPlanIds.value = newHighlightIds
|
|
|
selectedPlanId.value = newHighlightIds[0]
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
} else {
|
|
|
ElMessage.error(res.msg)
|
|
|
}
|
|
|
|
|
|
})
|
|
|
}
|
|
|
|
|
|
const processData = (data) => {
|
|
|
const result = {};
|
|
|
|
|
|
data.forEach(record => {
|
|
|
const deptName = record.department_resources_name;
|
|
|
if (!result[deptName]) {
|
|
|
result[deptName] = {};
|
|
|
}
|
|
|
|
|
|
const date = record.date;
|
|
|
if (!result[deptName][date]) {
|
|
|
result[deptName][date] = [];
|
|
|
}
|
|
|
|
|
|
// 计算剩余号数
|
|
|
record.remaining_count = record.count - record.used_count;
|
|
|
|
|
|
// 添加到对应日期的列表中
|
|
|
result[deptName][date].push({
|
|
|
id: record.id,
|
|
|
roster_id: record.roster_id,
|
|
|
weekname: record.weekname,
|
|
|
begin_time: record.begin_time,
|
|
|
end_time: record.end_time,
|
|
|
remaining_count: record.remaining_count,
|
|
|
status: record.status
|
|
|
// 如果需要,可以在这里添加其他字段
|
|
|
});
|
|
|
});
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
const zhenshiClick = (zhenshi) => {
|
|
|
activeZhenShi.value = zhenshi
|
|
|
selectedPlanId.value = 0
|
|
|
highlightedPlanIds.value = []
|
|
|
GetEnablePlanFunc()
|
|
|
}
|
|
|
// 从已分配或已预约的行中,收集在当前排班下可高亮的号源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 && !ids.includes(plan.id)) ids.push(plan.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 && !ids.includes(plan.id)) ids.push(plan.id)
|
|
|
}
|
|
|
}
|
|
|
return ids
|
|
|
}
|
|
|
const PlanClick = (planid) => {
|
|
|
console.log(planid)
|
|
|
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
|
|
|
highlightedPlanIds.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 = 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: 'optimal_time',
|
|
|
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) {
|
|
|
// 更新显示列表
|
|
|
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 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 = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
|
|
|
crossMsg += '<tr style="background:#f5f5f5;"><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">序号</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">项目名称</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">检查室</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">日期</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">时间段</td></tr>'
|
|
|
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 += '<tr style="background:' + bgColor + ';"><td style="padding:4px 8px;border:1px solid #ddd;">' + p.idx + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.entrust + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.room + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.timeSlot + '</td></tr>'
|
|
|
})
|
|
|
crossMsg += '</table>'
|
|
|
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 {
|
|
|
ElMessage.error(res.msg)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
// 单天全检按钮点击
|
|
|
const fullDayClick = () => {
|
|
|
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) {
|
|
|
// 更新显示列表
|
|
|
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) {
|
|
|
// 跨时段检测
|
|
|
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 = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
|
|
|
crossMsg += '<tr style="background:#f5f5f5;"><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">序号</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">项目名称</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">检查室</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">日期</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">时间段</td></tr>'
|
|
|
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 += '<tr style="background:' + bgColor + ';"><td style="padding:4px 8px;border:1px solid #ddd;">' + p.idx + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.entrust + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.room + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + p.timeSlot + '</td></tr>'
|
|
|
})
|
|
|
crossMsg += '</table>'
|
|
|
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: 'same_day_slot',
|
|
|
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)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
const checkDaijianFuc = () => {
|
|
|
planLoading.value = true
|
|
|
CheckIsDaiJian({
|
|
|
reg_num: props.reg_num,
|
|
|
planid: selectedPlanId.value
|
|
|
}).then(res => {
|
|
|
planLoading.value = false
|
|
|
if (res.status) {
|
|
|
|
|
|
} else {
|
|
|
ElMessageBox.confirm(
|
|
|
res.msg,
|
|
|
'提示', {
|
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning',
|
|
|
}
|
|
|
)
|
|
|
.then(() => {
|
|
|
|
|
|
})
|
|
|
.catch(() => {
|
|
|
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
const YuYueButtonClick = (type) => {
|
|
|
if (selectedEntrustId.length == 0) {
|
|
|
ElMessage.error("请选择检查项目")
|
|
|
return false;
|
|
|
}
|
|
|
if (selectedPlanId.value == 0 || selectedPlanId.value == '' || selectedPlanId.value==null) {
|
|
|
ElMessage.error("请选择号源")
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
let msg='确定预约此时间吗?'
|
|
|
if(type==2){
|
|
|
msg='确定改约至此时间吗?'
|
|
|
}
|
|
|
ElMessageBox.confirm(
|
|
|
msg,
|
|
|
'提示', {
|
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning',
|
|
|
}
|
|
|
)
|
|
|
.then(() => {
|
|
|
startYuYue(type)
|
|
|
})
|
|
|
.catch(() => {
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
const startYuYue = async (type) => {
|
|
|
planLoading.value = true
|
|
|
|
|
|
// 缓存未勾选但已有临时匹配号源的项目
|
|
|
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
|
|
|
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)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
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)
|
|
|
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 = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
|
|
|
html += '<tr style="background:#f5f5f5;"><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">序号</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">项目名称</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">检查室</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">日期</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">时间段</td><td style="padding:4px 8px;border:1px solid #ddd;font-weight:700;">结果</td></tr>'
|
|
|
let idx = 1
|
|
|
successItems.forEach(item => {
|
|
|
html += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (idx++) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + item.name + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + item.room + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + item.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + item.time + '</td><td style="padding:4px 8px;border:1px solid #ddd;color:green;">预约成功</td></tr>'
|
|
|
})
|
|
|
failItems.forEach(f => {
|
|
|
html += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (idx++) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + f.name + '</td><td style="padding:4px 8px;border:1px solid #ddd;" colspan="3">—</td><td style="padding:4px 8px;border:1px solid #ddd;color:red;">' + f.msg + '</td></tr>'
|
|
|
})
|
|
|
html += '</table>'
|
|
|
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 = () => {
|
|
|
|
|
|
ElMessageBox.confirm(
|
|
|
'确定取消预约吗?',
|
|
|
'提示', {
|
|
|
confirmButtonText: '确定',
|
|
|
cancelButtonText: '取消',
|
|
|
type: 'warning',
|
|
|
}
|
|
|
)
|
|
|
.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({
|
|
|
MainListId: v.id,
|
|
|
reg_num: v.reg_num,
|
|
|
do_user:props.do_user,
|
|
|
}).then(res => {
|
|
|
if (res.status) {
|
|
|
ElMessage.success('取消成功')
|
|
|
} else {
|
|
|
ElMessage.error(res.msg)
|
|
|
}
|
|
|
}).catch(err => {
|
|
|
ElMessage.error('取消失败')
|
|
|
console.error(err)
|
|
|
})
|
|
|
})
|
|
|
|
|
|
// 等待所有请求完成
|
|
|
await Promise.all(promises)
|
|
|
|
|
|
loading.value = false
|
|
|
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)
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
const GetConfigInfoFunc=()=>{
|
|
|
GetConfigInfo2({
|
|
|
config_arrs: ['开启申请单pdf','医生端打印'],
|
|
|
}).then(res => {
|
|
|
if(res.status){
|
|
|
systemConfigs.value=res.data.list
|
|
|
systemConfigs.value.forEach((v,i)=>{
|
|
|
console.log(props.appointment_type)
|
|
|
if(v.label=='医生端打印' && v.value==="0" && props.appointment_type==1){
|
|
|
auto_print.value=[]
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
//生成pdf文件
|
|
|
const CreateJianChaShenQingDanPdfFunc=(entrustIds)=>{
|
|
|
const ids = entrustIds || selectedEntrustId.value
|
|
|
CreateJianChaShenQingDanPdf({
|
|
|
OrderNoList: ids,
|
|
|
}).then(res => {
|
|
|
if(res.status){
|
|
|
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
//打印申请单
|
|
|
let shenqingdan_list = ref([])
|
|
|
const print_shenqingdan = (entrustIds) => {
|
|
|
const ids = entrustIds || selectedEntrustId.value
|
|
|
getMainDetail({
|
|
|
regnum: props.reg_num,
|
|
|
entrustid: ids.join(','),
|
|
|
episodeid: props.episode_id,
|
|
|
appointment_type: props.appointment_type
|
|
|
}).then(res => {
|
|
|
if (res.status) {
|
|
|
let enable = true
|
|
|
shenqingdan_list.value = res.data.info
|
|
|
shenqingdan_list.value.forEach((v, i) => {
|
|
|
if (v.maininfo.list_status != 1) {
|
|
|
ElMessage.error(v.maininfo.entrust + " 不可打印,请重新选择")
|
|
|
enable = false
|
|
|
}
|
|
|
})
|
|
|
if (enable) {
|
|
|
shenqingdan_show.value = true
|
|
|
setTimeout(function() {
|
|
|
print_shenqingdan_button.value.$el.click();
|
|
|
shenqingdan_show.value = false
|
|
|
}, 500)
|
|
|
}
|
|
|
} else {
|
|
|
ElMessage.error(res.msg)
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
const DatePickerChange = () => {
|
|
|
activeZhenShi.value=''
|
|
|
date_list.value = getDatesAfter(startDate.value)
|
|
|
console.log(date_list.value)
|
|
|
GetEnablePlanFunc()
|
|
|
}
|
|
|
|
|
|
function formatDateLocal(date) {
|
|
|
const year = date.getFullYear();
|
|
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
const day = String(date.getDate()).padStart(2, '0');
|
|
|
return `${year}-${month}-${day}`;
|
|
|
}
|
|
|
|
|
|
function getDatesAfter(startDate = new Date(), days = 15) {
|
|
|
const date = new Date(startDate); // 转换为 Date 对象
|
|
|
const dates = [];
|
|
|
|
|
|
if (isNaN(date.getTime())) {
|
|
|
throw new Error("无效的日期格式");
|
|
|
}
|
|
|
|
|
|
for (let i = 0; i < days; i++) {
|
|
|
const nextDate = new Date(date);
|
|
|
nextDate.setDate(date.getDate() + i);
|
|
|
|
|
|
const formattedDate = formatDateLocal(nextDate);
|
|
|
dates.push(formattedDate);
|
|
|
}
|
|
|
|
|
|
return dates;
|
|
|
}
|
|
|
function isValidDate(dateString) {
|
|
|
// 简单的正则表达式来验证日期格式为 YYYY-MM-DD
|
|
|
const datePattern = /^\d{4}-\d{2}-\d{2}$/;
|
|
|
if (!datePattern.test(dateString)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 创建 Date 对象并检查是否为有效日期
|
|
|
const date = new Date(dateString);
|
|
|
return date.toString() !== "Invalid Date" &&
|
|
|
!isNaN(date.getTime());
|
|
|
}
|
|
|
|
|
|
function checkDateDifference15Day(date1, date2) {
|
|
|
// 校验日期格式是否正确
|
|
|
if (!isValidDate(date1) || !isValidDate(date2)) {
|
|
|
console.error("日期格式不正确,请使用 YYYY-MM-DD");
|
|
|
return false; // 或者抛出异常、提示用户等
|
|
|
}
|
|
|
|
|
|
const startDate = new Date(date1);
|
|
|
const endDate = new Date(date2);
|
|
|
|
|
|
// 计算时间差(毫秒)
|
|
|
const diffInMs = endDate - startDate;
|
|
|
|
|
|
// 转换为天数
|
|
|
const diffInDays = diffInMs / (1000 * 60 * 60 * 24);
|
|
|
|
|
|
return diffInDays > 15;
|
|
|
}
|
|
|
function getTodayDate() {
|
|
|
const today = new Date();
|
|
|
|
|
|
const year = today.getFullYear(); // 年份,如 2025
|
|
|
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份从 0 开始,所以要 +1
|
|
|
const day = String(today.getDate()).padStart(2, '0'); // 日期
|
|
|
|
|
|
return `${year}-${month}-${day}`;
|
|
|
}
|
|
|
let onMountedStatus=ref(false)
|
|
|
onMounted(() => {
|
|
|
onMountedStatus.value=true;
|
|
|
GetConfigInfoFunc()
|
|
|
date_list.value = getDatesAfter()
|
|
|
GetMainInfo()
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.YuYue202506 {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
height: 100%;
|
|
|
}
|
|
|
|
|
|
.patientInfo {
|
|
|
display: flex;
|
|
|
flex-shrink: 0;
|
|
|
.item{
|
|
|
margin-right: 18px;
|
|
|
}
|
|
|
.name {
|
|
|
font-size: 20px;
|
|
|
font-weight: 700;
|
|
|
}
|
|
|
|
|
|
.value {
|
|
|
font-size: 18px;
|
|
|
font-weight: 700;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.entrustList {
|
|
|
flex: 1;
|
|
|
min-height: 0;
|
|
|
overflow: auto;
|
|
|
.errMsg {
|
|
|
color: #f27d7d;
|
|
|
font-weight: 700;
|
|
|
opacity: 1 !important;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.planInfo {
|
|
|
max-height: 600px;
|
|
|
overflow: auto;
|
|
|
flex-shrink: 0;
|
|
|
.planTable {
|
|
|
width: 100%;
|
|
|
background-color: #fff;
|
|
|
text-align: center;
|
|
|
border: 1px solid #f1f1f1;
|
|
|
border-collapse: collapse;
|
|
|
/* 合并边框 */
|
|
|
color: #333;
|
|
|
|
|
|
td {
|
|
|
border: 1px solid #f1f1f1;
|
|
|
padding: 6px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.table_plan_row td:first-child {
|
|
|
background-color: #f1f1f1;
|
|
|
border-bottom: 1px solid #e8e8e8;
|
|
|
}
|
|
|
|
|
|
.table_plan_row> :not(:first-child):hover {
|
|
|
background-color: #aeebf0;
|
|
|
cursor: pointer;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.planActive {
|
|
|
background-color: #5bc0de;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
.plandisable {
|
|
|
pointer-events: none;
|
|
|
opacity: 0.4;
|
|
|
}
|
|
|
|
|
|
.shuxian {
|
|
|
border-left: 1px solid #dfdfdf;
|
|
|
margin-left: 40px;
|
|
|
margin-right: 40px;
|
|
|
}
|
|
|
|
|
|
.do_button_recommend {
|
|
|
width: 180px;
|
|
|
}
|
|
|
|
|
|
.do_button {
|
|
|
width: 100px;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.ZhenShiButton {
|
|
|
text-align: center;
|
|
|
font-size: 14px;
|
|
|
background-color: #fff;
|
|
|
border: 1px solid #e8e8e8;
|
|
|
width: 120px;
|
|
|
cursor: default;
|
|
|
display: flex;
|
|
|
justify-content: center; /* 水平居中 */
|
|
|
align-items: center; /* 垂直居中 */
|
|
|
padding: 4px;
|
|
|
}
|
|
|
|
|
|
.zhenshiButton_active {
|
|
|
background-color: #5bc0de;
|
|
|
color: #fff;
|
|
|
}
|
|
|
|
|
|
::v-deep .el-table .disabled-row {
|
|
|
background-color: #f2e3e2;
|
|
|
//pointer-events: none;
|
|
|
/* 禁用鼠标事件 */
|
|
|
opacity: 0.6;
|
|
|
/* 降低透明度 */
|
|
|
}
|
|
|
|
|
|
::v-deep .el-table .selected-row {
|
|
|
background-color: #9cd0de;
|
|
|
|
|
|
}
|
|
|
</style>
|
|
|
|
|
|
<style>
|
|
|
.tip-pre-line {
|
|
|
white-space: pre-line;
|
|
|
font-size: 16px;
|
|
|
}
|
|
|
</style> |