|
|
|
@ -363,21 +363,23 @@ |
|
|
|
</el-button-group> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="flex hosColorType" v-if="hosList.length > 1"> |
|
|
|
<div class="flex gap12" v-for="(item, index) in hosList" :key="index"> |
|
|
|
<span class="color-tag" :style="{ backgroundColor: colorPalette[index] }"></span> |
|
|
|
<span>{{ item.h_depart_name }}</span> |
|
|
|
<div class="flex hosColorType" v-if="activeHosList.length > 1"> |
|
|
|
<div v-for="(item, index) in activeHosList" :key="index" > |
|
|
|
<div class="flex gap12" v-if="item.status == '1'"> |
|
|
|
<span class="color-tag" :style="{ backgroundColor: colorPalette[index] }"></span> |
|
|
|
<span>{{ item.h_depart_name }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="calendar-container"> |
|
|
|
<el-calendar v-model="currentDay" :first-day-of-week="7" @update:modelValue="onCalendarMonthChange"> |
|
|
|
<template slot="dateCell" slot-scope="{date, data}"> |
|
|
|
<el-tooltip placement="bottom" :disabled="hosList.length == 1" |
|
|
|
<el-tooltip placement="bottom" :disabled="activeHosList.length == 1" |
|
|
|
v-if="hasScheduleData(data.day, date)" popper-class="schedule-tooltip"> |
|
|
|
<!-- getDateCellClass 控制单独医院 的类名--> |
|
|
|
<div class="calendar-date" v-if="isFutureOrToday(date)" |
|
|
|
@click="handleDateClick(data.day, $event, date, data)" |
|
|
|
:class="[hosList.length == 1 ? getDateCellClass(data.day) : '', (isConflictDate(data.day) && !is_allow_coincide) ? 'conflict-date' : '', !isCurrentMonth(date) ? 'not-current-month' : '']"> |
|
|
|
:class="[activeHosList.length == 1 ? getDateCellClass(data.day) : '', (isConflictDate(data.day) && !is_allow_coincide) ? 'conflict-date' : '', !isCurrentMonth(date) ? 'not-current-month' : '']"> |
|
|
|
<div class="date-header flex-between"> |
|
|
|
<div class="flex gap12"> |
|
|
|
<span class="date-text">{{ getDayNumber(data.day) }}</span> |
|
|
|
@ -399,9 +401,9 @@ |
|
|
|
<div v-if="key !== '0' && getDateSchedule(data.day)[key] && getDateSchedule(data.day)[key].length > 0" |
|
|
|
class="schedule-item" :class="getScheduleItemClass(data.day, key)"> |
|
|
|
<span class="shift-type" |
|
|
|
:style="(hosList.length == 1 && getDateCellClass(data.day) == 'shift-type-0') ? 'text-decoration:line-through' : ''">{{ |
|
|
|
:style="(activeHosList.length == 1 && getDateCellClass(data.day) == 'shift-type-0') ? 'text-decoration:line-through' : ''">{{ |
|
|
|
shiftType }}</span> |
|
|
|
<div class="hospital-tags" v-if="hosList.length > 1"> |
|
|
|
<div class="hospital-tags" v-if="activeHosList.length > 1"> |
|
|
|
<span v-for="hospital in getDateSchedule(data.day)[key]" |
|
|
|
:key="hospital.hid" |
|
|
|
:class="getColorTagConfig(data.day, hospital.hid, key).class" |
|
|
|
@ -630,8 +632,8 @@ |
|
|
|
{{ currentEditingDate }}{{ isToday(currentEditingDate) ? '(今日)' : '' }} |
|
|
|
</p> |
|
|
|
<el-form> |
|
|
|
<div class="flex mb24"> |
|
|
|
<span class="" style="width: 50px;margin-right: 24px;">上午班</span> |
|
|
|
<div class="flex mb24 gap12"> |
|
|
|
<span class="" style="min-width: 50px;">上午班</span> |
|
|
|
<div class="select-container"> |
|
|
|
<div class="selected-hospitals-display" @click="toggleAfternoonDropdown('morn')"> |
|
|
|
<div class="flex"> |
|
|
|
@ -657,8 +659,8 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="flex"> |
|
|
|
<span style="width: 50px;margin-right: 24px;">下午班</span> |
|
|
|
<div class="flex gap12"> |
|
|
|
<span style="min-width: 50px;">下午班</span> |
|
|
|
<div class="select-container"> |
|
|
|
<div class="selected-hospitals-display" @click="toggleAfternoonDropdown('after')"> |
|
|
|
<div class="flex"> |
|
|
|
@ -683,7 +685,6 @@ |
|
|
|
</el-option> |
|
|
|
</el-select> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</el-form> |
|
|
|
|
|
|
|
@ -1019,6 +1020,7 @@ export default { |
|
|
|
originalAfternoonSelected: [], // 保存原始下午选中状态 |
|
|
|
forceTime: Date.now(), |
|
|
|
singleCurrentPlan:null, |
|
|
|
activeHosList:[], |
|
|
|
} |
|
|
|
}, |
|
|
|
created() { |
|
|
|
@ -1064,12 +1066,16 @@ export default { |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
|
|
|
|
// 生成医院颜色映射对象 |
|
|
|
// 根据医院列表生成颜色映射表,循环使用调色板中的颜色 |
|
|
|
hospitalColorMap() { |
|
|
|
const colorMap = {}; |
|
|
|
this.hosListCopy.forEach((hospital, index) => { |
|
|
|
// old |
|
|
|
// this.hosListCopy.forEach((hospital, index) => { |
|
|
|
// colorMap[hospital.hid] = this.colorPalette[index % this.colorPalette.length]; |
|
|
|
// }); |
|
|
|
// new 已筛选出状态为1的 |
|
|
|
this.activeHosList.forEach((hospital, index) => { |
|
|
|
colorMap[hospital.hid] = this.colorPalette[index % this.colorPalette.length]; |
|
|
|
}); |
|
|
|
return colorMap; |
|
|
|
@ -1427,7 +1433,7 @@ export default { |
|
|
|
const hospitals = this.getHospitalsByDate(dateString); |
|
|
|
|
|
|
|
// 重构医院数据,确保正确设置上下午出诊状态 |
|
|
|
this.hosList = this.hosListCopy.map(item => { |
|
|
|
this.hosList = this.activeHosList.map(item => { |
|
|
|
let hospitalInfo = { |
|
|
|
hid: item.hid, |
|
|
|
name: item.h_depart_name, |
|
|
|
@ -1726,11 +1732,15 @@ export default { |
|
|
|
getColorTagConfig(dateStr, hospitalId, shiftType) { |
|
|
|
const schedule = this.getDateSchedule(dateStr); |
|
|
|
if (!schedule || !schedule[shiftType]) return { class: 'color-tag', style: {} }; |
|
|
|
|
|
|
|
|
|
|
|
const hospital = schedule[shiftType].find(h => h.hid === hospitalId); |
|
|
|
if (!hospital) return { class: 'color-tag', style: {} }; |
|
|
|
|
|
|
|
const hospitalColor = this.getHospitalColor(hospitalId); |
|
|
|
const hospitalColor = this.hospitalColorMap[hospitalId]; |
|
|
|
|
|
|
|
// 如果没有找到颜色,说明这个医院不在活跃列表中 |
|
|
|
if (!hospitalColor) { |
|
|
|
return { class: 'color-tag hidden-tag', style: { backgroundColor: '#CCCCCC' } }; |
|
|
|
} |
|
|
|
|
|
|
|
// 如果是取消的班次 |
|
|
|
if (hospital.isCancelled) { |
|
|
|
@ -1984,20 +1994,39 @@ export default { |
|
|
|
this.hosList = Object.keys(list).map(item => { |
|
|
|
return { |
|
|
|
hid: item, |
|
|
|
h_depart_name: list[item].h_depart_name |
|
|
|
h_depart_name: list[item].h_depart_name, |
|
|
|
status: list[item].status,//医院状态 |
|
|
|
} |
|
|
|
}); |
|
|
|
// 存储一份副本,用于后续操作 |
|
|
|
// 假设医院状态 后续接口更新后 删除掉 |
|
|
|
this.hosList[0].status = '1' |
|
|
|
this.hosList[1].status = '0' |
|
|
|
this.hosList[2].status = '1' |
|
|
|
|
|
|
|
//存储一份副本,用于后续操作 |
|
|
|
this.hosListCopy = JSON.parse(JSON.stringify(this.hosList)) |
|
|
|
|
|
|
|
// 保存原始数据 |
|
|
|
this.rawScheduleData = JSON.parse(JSON.stringify(list)); |
|
|
|
// new add |
|
|
|
this.activeHosList = this.hosList.filter(item => item.status == '1'); // 只包含状态为1的医院 |
|
|
|
|
|
|
|
|
|
|
|
//old 保存原始数据 |
|
|
|
// this.rawScheduleData = JSON.parse(JSON.stringify(list)); |
|
|
|
|
|
|
|
//new 保存原始数据 |
|
|
|
// (1) |
|
|
|
this.rawScheduleData={}; |
|
|
|
this.activeHosList.forEach(hospital => { |
|
|
|
if (list[hospital.hid]) { |
|
|
|
this.rawScheduleData[hospital.hid] = JSON.parse(JSON.stringify(list[hospital.hid])); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 初始化当前月份的排班数据 |
|
|
|
this.generateMonthSchedule(this.currentDay); |
|
|
|
this.countMonthlyConflicts(); |
|
|
|
|
|
|
|
this.hosLength = Object.keys(list).length; |
|
|
|
this.hosLength = Object.keys(this.activeHosList).length; |
|
|
|
|
|
|
|
} |
|
|
|
}).catch(error => { |
|
|
|
@ -2040,6 +2069,19 @@ export default { |
|
|
|
// 清空临时调整数据 |
|
|
|
this.tempAdjustments = {}; |
|
|
|
|
|
|
|
// new |
|
|
|
// 过滤掉状态为0的医院数据 |
|
|
|
const activeHospitalIds = this.hosList.map(hospital => hospital.hid); |
|
|
|
const filteredScheduleData = {}; |
|
|
|
|
|
|
|
Object.keys(this.rawScheduleData).forEach(hospitalId => { |
|
|
|
if (activeHospitalIds.includes(hospitalId)) { |
|
|
|
filteredScheduleData[hospitalId] = this.rawScheduleData[hospitalId]; |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 使用过滤后的数据生成排班 |
|
|
|
|
|
|
|
while (currentDate <= endDate) { |
|
|
|
const dateStr = this.formatDate(currentDate); |
|
|
|
const daySchedule = this.getScheduleForDate(currentDate); |
|
|
|
@ -2061,6 +2103,8 @@ export default { |
|
|
|
console.log(this.calendarList,'===this.calendarList:'); |
|
|
|
}, |
|
|
|
addHospitalToSchedule(daySchedule, hospitalId, hospital, plan, workDesc) { |
|
|
|
const isActiveHospital = this.activeHosList.some(h => h.hid === hospitalId); |
|
|
|
if (!isActiveHospital) return; // 如果不是活跃医院,直接返回 |
|
|
|
const shiftType = plan.toString(); |
|
|
|
const dateStr = daySchedule._dateStr; |
|
|
|
const originalPlan = this.getOriginalPlan(dateStr, hospitalId); |
|
|
|
@ -2137,8 +2181,15 @@ export default { |
|
|
|
_conflicts: [], |
|
|
|
_dateStr: dateStr // 添加日期标识 |
|
|
|
}; |
|
|
|
//new 使用传入的过滤后数据或原始数据 |
|
|
|
const hospitalsToProcess = this.activeHosList.map(hospital => hospital.hid); |
|
|
|
|
|
|
|
Object.keys(this.rawScheduleData).forEach(hospitalId => { |
|
|
|
// old |
|
|
|
// Object.keys(this.rawScheduleData).forEach(hospitalId => { |
|
|
|
// const hospital = this.rawScheduleData[hospitalId]; |
|
|
|
|
|
|
|
// new |
|
|
|
hospitalsToProcess.forEach(hospitalId => { |
|
|
|
const hospital = this.rawScheduleData[hospitalId]; |
|
|
|
const { worktime_no_fixed, worktime_list, temp_change_worktime } = hospital; |
|
|
|
|
|
|
|
@ -2190,8 +2241,6 @@ export default { |
|
|
|
|
|
|
|
// 检查冲突 |
|
|
|
this.checkScheduleConflicts(daySchedule, dateStr); |
|
|
|
// console.log(daySchedule,'daySchedule==='); |
|
|
|
|
|
|
|
return Object.keys(daySchedule).length > 1 ? daySchedule : null; |
|
|
|
}, |
|
|
|
// 检查排班冲突 |
|
|
|
@ -3236,6 +3285,8 @@ export default { |
|
|
|
.select-container { |
|
|
|
position: relative; |
|
|
|
flex: 1; |
|
|
|
/* 确保容器不超出父元素 */ |
|
|
|
max-width: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.conflictTip { |
|
|
|
@ -3256,8 +3307,8 @@ export default { |
|
|
|
text-align: center; |
|
|
|
letter-spacing: 0.08em; |
|
|
|
color: #FF4D4F; |
|
|
|
box-sizing: border-box; |
|
|
|
margin-right: 6px; |
|
|
|
flex-shrink: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.selected-hospitals-display { |
|
|
|
@ -3272,6 +3323,8 @@ export default { |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
transition: border-color 0.2s; |
|
|
|
width: 100%; |
|
|
|
box-sizing: border-box; |
|
|
|
} |
|
|
|
|
|
|
|
.selected-hospitals-display:hover { |
|
|
|
@ -3282,6 +3335,30 @@ export default { |
|
|
|
border-color: #409EFF; |
|
|
|
} |
|
|
|
|
|
|
|
.overHostext { |
|
|
|
white-space: nowrap; |
|
|
|
text-overflow: ellipsis; |
|
|
|
overflow: hidden; |
|
|
|
flex: 1; |
|
|
|
min-width: 0; /* 重要:确保文本截断生效 */ |
|
|
|
overflow-x: auto; |
|
|
|
padding-right: 8px; |
|
|
|
} |
|
|
|
|
|
|
|
/* 隐藏滚动条但保持滚动功能 */ |
|
|
|
.overHostext::-webkit-scrollbar { |
|
|
|
height: 3px; |
|
|
|
} |
|
|
|
|
|
|
|
.overHostext::-webkit-scrollbar-track { |
|
|
|
background: #f1f1f1; |
|
|
|
} |
|
|
|
|
|
|
|
.overHostext::-webkit-scrollbar-thumb { |
|
|
|
background: #c1c1c1; |
|
|
|
border-radius: 3px; |
|
|
|
} |
|
|
|
|
|
|
|
.hidden-select { |
|
|
|
position: absolute; |
|
|
|
top: 0; |
|
|
|
@ -3289,8 +3366,8 @@ export default { |
|
|
|
width: 100%; |
|
|
|
opacity: 0; |
|
|
|
z-index: 1; |
|
|
|
// pointer-events: none; |
|
|
|
} |
|
|
|
|
|
|
|
// 下拉框定位-- |
|
|
|
|
|
|
|
.tooltip-content { |
|
|
|
@ -3493,6 +3570,10 @@ export default { |
|
|
|
border: 1px solid rgba(0, 0, 0, 0.1); |
|
|
|
} |
|
|
|
|
|
|
|
.hidden-tag { |
|
|
|
display: none !important; |
|
|
|
} |
|
|
|
|
|
|
|
// 取消框透明度调整 |
|
|
|
.opacity-tag { |
|
|
|
opacity: .6; |
|
|
|
|