You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2040 lines
76 KiB
Vue

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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.bedno">床号:<span class="value">{{patientInfo.bedno}}</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="conflictDialogVisible" title="时段冲突" width="800">
<div style="display: flex; align-items: flex-start; gap: 12px;">
<el-icon style="color: #F56C6C; 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="conflictDialogHtml"></div>
</div>
</div>
<template #footer>
<el-button type="primary" @click="conflictDialogVisible = 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>
<el-dialog v-model="recommendResultVisible" 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="recommendResultHtml"></div>
</div>
<template #footer>
<el-button type="primary" @click="recommendResultVisible = 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 cachedRecommendResultData = ref(null) // 缓存推荐结果 dialog 数据:{ html, idx }
let conflictDialogVisible = ref(false)
let conflictDialogHtml = ref('')
let resultDialogVisible = ref(false)
let resultDialogHtml = ref('')
let recommendResultVisible = ref(false)
let recommendResultHtml = 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
}
}
// 检查缓存中是否有推荐结果 dialog 需要弹出
if (cachedRecommendResultData.value) {
const currentIdx = entrustTableDate.value.findIndex(
r => selectedMianListId.value.includes(r.id)
) + 1
if (currentIdx === cachedRecommendResultData.value.idx) {
recommendResultHtml.value = cachedRecommendResultData.value.html
recommendResultVisible.value = true
cachedRecommendResultData.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:#d5dce6;"><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' ? '#d5dce6' : '#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 matchedIds = new Set(res.data.map(v => v.id))
const unmatched = items.filter(v => !matchedIds.has(v.id))
if (unmatched.length > 0) {
let html = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
html += '<tr style="background:#d5dce6;"><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
res.data.forEach(v => {
const entrustName = entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
html += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (idx++) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + entrustName + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + v.department_resources_name + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + v.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + v.begin_time?.substring(0, 5) + '-' + v.end_time?.substring(0, 5) + '</td><td style="padding:4px 8px;border:1px solid #ddd;color:green;">✅ 成功匹配</td></tr>'
})
unmatched.forEach(v => {
const entrustName = entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
html += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (idx++) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + entrustName + '</td><td style="padding:4px 8px;border:1px solid #ddd;" colspan="3">—</td><td style="padding:4px 8px;border:1px solid #ddd;color:red;">❌ 未找到合适号源</td></tr>'
})
html += '</table>'
// 计算未匹配项目的最小序号
const unmatchedIndices = unmatched.map(v => entrustTableDate.value.findIndex(r => r.id === v.id) + 1).filter(i => i > 0)
const minUnmatchedIdx = Math.min(...unmatchedIndices)
const selectedIdx = entrustTableDate.value.findIndex(
r => selectedMianListId.value.includes(r.id)
) + 1
if (selectedIdx === minUnmatchedIdx) {
recommendResultHtml.value = html
recommendResultVisible.value = true
} else {
cachedRecommendResultData.value = { html: html, idx: minUnmatchedIdx }
}
}
// 更新高亮
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:#d5dce6;"><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' ? '#d5dce6' : '#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 html = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
html += '<tr style="background:#d5dce6;"><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
res.data.forEach(v => {
const entrustName = entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
html += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (idx++) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + entrustName + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + v.department_resources_name + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + v.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + v.begin_time?.substring(0, 5) + '-' + v.end_time?.substring(0, 5) + '</td><td style="padding:4px 8px;border:1px solid #ddd;color:green;">✅ 成功匹配</td></tr>'
})
unmatched.forEach(v => {
const entrustName = entrustTableDate.value.find(r => r.id === v.id)?.entrust || ''
html += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (idx++) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + entrustName + '</td><td style="padding:4px 8px;border:1px solid #ddd;" colspan="3">—</td><td style="padding:4px 8px;border:1px solid #ddd;color:red;">❌ 未找到合适号源</td></tr>'
})
html += '</table>'
recommendResultHtml.value = html
recommendResultVisible.value = true
} 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:#d5dce6;"><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' ? '#d5dce6' : '#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
// 获取当前选中排班的时间信息
const selectedPlan = cachedPlans.value.find(p => p.id === selectedPlanId.value)
if (!selectedPlan) {
planLoading.value = false
return
}
const planStart = selectedPlan.date + ' ' + selectedPlan.begin_time
const planEnd = selectedPlan.date + ' ' + selectedPlan.end_time
const currentRoom = selectedPlan.department_resources_name
CheckIsDaiJian({
reg_num: props.reg_num,
planid: selectedPlanId.value
}).then(res => {
planLoading.value = false
let allConflicts = []
// ① 后端返回的已预约冲突(过滤同检查室)
if (!res.status && res.data?.conflicts) {
allConflicts = allConflicts.concat(
res.data.conflicts.filter(c => c.room_name !== currentRoom)
)
}
// ② 前端临时匹配的冲突(过滤同检查室)
entrustTableDate.value.forEach(item => {
if (item.list_status !== 0 || !item.temp_plan_id || !item.reservation_date) return
const itemRoom = item.department_resources?.department_resources_name
if (itemRoom === currentRoom) return // 同检查室允许重叠
const itemStart = item.reservation_date + ' ' + item.period_begin_time
const itemEnd = item.reservation_date + ' ' + item.period_end_time
if (itemStart <= planEnd && planStart <= itemEnd) {
const exists = allConflicts.some(c =>
c.entrust === item.entrust && c.date === item.reservation_date
)
if (!exists) {
allConflicts.push({
entrust: item.entrust,
date: item.reservation_date,
begin_time: item.period_begin_time?.substring(0, 5),
end_time: item.period_end_time?.substring(0, 5),
room_name: item.department_resources?.department_resources_name || '',
})
}
}
})
// ③ 展示冲突(使用独立 dialog
if (allConflicts.length > 0) {
let msg = '<table style="width:100%;border-collapse:collapse;font-size:14px;">'
msg += '<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>'
allConflicts.forEach((c, i) => {
msg += '<tr><td style="padding:4px 8px;border:1px solid #ddd;">' + (i + 1) + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + c.entrust + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + (c.room_name || '') + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + c.date + '</td><td style="padding:4px 8px;border:1px solid #ddd;">' + c.begin_time + '-' + c.end_time + '</td></tr>'
})
msg += '</table>'
conflictDialogHtml.value = msg
conflictDialogVisible.value = true
} else {
// 无冲突,继续预约流程
// 由调用方处理
}
})
}
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;
align-items: center;
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>