894 lines
26 KiB
Vue
894 lines
26 KiB
Vue
<template>
|
||
<div class="doctorschedule-container">
|
||
<div class="doctorschedule-header">
|
||
<h2 class="doctorschedule-title">医生排班</h2>
|
||
</div>
|
||
|
||
<div class="doctorschedule-content">
|
||
<!-- 筛选条件 -->
|
||
<div class="filter-condition">
|
||
<span class="filter-label">卫生机构</span>
|
||
<el-select v-model="filterParams.orgName" class="filter-select">
|
||
<el-option label="演示医院" value="演示医院"></el-option>
|
||
</el-select>
|
||
|
||
<span class="filter-label">科室名称</span>
|
||
<el-select v-model="filterParams.deptName" class="filter-select">
|
||
<el-option label="测试内科" value="测试内科"></el-option>
|
||
</el-select>
|
||
|
||
<span class="filter-label">开始日期</span>
|
||
<el-date-picker
|
||
v-model="filterParams.startDate"
|
||
type="date"
|
||
placeholder="选择日期"
|
||
class="filter-date-picker"
|
||
/>
|
||
|
||
<span class="filter-label">排班类型</span>
|
||
<div class="radio-group">
|
||
<el-radio v-model="filterParams.appointmentType" label="普通" @change="handleAppointmentTypeChange">普通</el-radio>
|
||
<el-radio v-model="filterParams.appointmentType" label="专家" @change="handleAppointmentTypeChange">专家</el-radio>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 排班表格 -->
|
||
<div class="schedule-table-container">
|
||
<!-- 按日期分组显示排班 -->
|
||
<div v-for="(dateGroup, index) in groupedSchedule" :key="index" class="daily-schedule">
|
||
<div class="daily-header">
|
||
<span class="date-text">{{ dateGroup.date }}</span>
|
||
<span class="weekday-text">{{ dateGroup.weekday }}</span>
|
||
</div>
|
||
<el-table :data="dateGroup.items" border style="width: 100%" class="schedule-table">
|
||
<el-table-column prop="timeSlot" label="时段" width="100"></el-table-column>
|
||
<el-table-column prop="doctorName" :label="filterParams.appointmentType === '专家' ? '专家' : '医生'" width="150">
|
||
<template #default="scope">
|
||
<el-select
|
||
v-model="scope.row.doctorName"
|
||
placeholder="请选"
|
||
class="inline-select"
|
||
:disabled="!isEditMode"
|
||
>
|
||
<el-option
|
||
v-for="doctor in getDoctorOptions(filterParams.appointmentType)"
|
||
:key="doctor.value"
|
||
:label="doctor.label"
|
||
:value="doctor.value"
|
||
></el-option>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="room" label="诊室" width="100">
|
||
<template #default="scope">
|
||
<el-select
|
||
v-model="scope.row.room"
|
||
placeholder="请选"
|
||
class="inline-select"
|
||
:disabled="!isEditMode"
|
||
>
|
||
<el-option label="诊室1" value="诊室1"></el-option>
|
||
<el-option label="诊室2" value="诊室2"></el-option>
|
||
<el-option label="诊室3" value="诊室3"></el-option>
|
||
<el-option label="诊室4" value="诊室4"></el-option>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="startTime" label="开始时间" width="120">
|
||
<template #default="scope">
|
||
<el-time-picker
|
||
v-model="scope.row.startTime"
|
||
type="time"
|
||
format="HH:mm"
|
||
value-format="HH:mm"
|
||
placeholder="选择开始时间"
|
||
:disabled="!isEditMode"
|
||
class="time-picker"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="endTime" label="结束时间" width="120">
|
||
<template #default="scope">
|
||
<el-time-picker
|
||
v-model="scope.row.endTime"
|
||
type="time"
|
||
format="HH:mm"
|
||
value-format="HH:mm"
|
||
placeholder="选择结束时间"
|
||
:disabled="!isEditMode"
|
||
class="time-picker"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="maxNumber" label="限号数量" width="80">
|
||
<template #default="scope">
|
||
<el-input
|
||
v-model="scope.row.maxNumber"
|
||
type="number"
|
||
:disabled="!isEditMode"
|
||
/>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="record" label="号源记录" width="80">
|
||
<template #default="scope">
|
||
<el-icon
|
||
@click="handleViewRecord(scope.row)"
|
||
class="record-icon"
|
||
title="查看号源记录"
|
||
>
|
||
<View />
|
||
</el-icon>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="appointmentItem" label="挂号项目" width="120">
|
||
<template #default="scope">
|
||
<el-select
|
||
v-model="scope.row.appointmentItem"
|
||
placeholder="请选"
|
||
class="inline-select"
|
||
:disabled="!isEditMode"
|
||
@change="handleAppointmentItemChange(scope.row)"
|
||
>
|
||
<el-option label="挂号费 50" value="挂号费 50"></el-option>
|
||
<el-option label="一般诊疗费 10" value="一般诊疗费 10"></el-option>
|
||
<el-option label="主任医师 27" value="主任医师 27"></el-option>
|
||
<el-option label="副主任 15" value="副主任 15"></el-option>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="registrationFee" label="挂号费(元)" width="100">
|
||
<template #default="scope">
|
||
<span>{{ scope.row.registrationFee || '0' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="clinicItem" label="诊查项目" width="150">
|
||
<template #default="scope">
|
||
<el-select
|
||
v-model="scope.row.clinicItem"
|
||
placeholder="请选择诊查项目"
|
||
class="inline-select"
|
||
:disabled="!isEditMode"
|
||
@change="handleClinicItemChange(scope.row)"
|
||
>
|
||
<el-option label="常规诊查" value="常规诊查"></el-option>
|
||
<el-option label="专科诊查" value="专科诊查"></el-option>
|
||
<el-option label="特殊诊查" value="特殊诊查"></el-option>
|
||
<el-option label="专家诊查" value="专家诊查"></el-option>
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="treatmentFee" label="诊疗费(元)" width="100">
|
||
<template #default="scope">
|
||
<span>{{ scope.row.treatmentFee || '0' }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="online" label="线上" width="60">
|
||
<template #default="scope">
|
||
<el-checkbox v-model="scope.row.online" :disabled="!isEditMode"></el-checkbox>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="stopClinic" label="停诊" width="60">
|
||
<template #default="scope">
|
||
<el-checkbox v-model="scope.row.stopClinic" :disabled="!isEditMode"></el-checkbox>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="stopReason" label="停诊原因" width="150">
|
||
<template #default="scope">
|
||
<el-input
|
||
v-model="scope.row.stopReason"
|
||
:placeholder="scope.row.stopClinic ? '请输入停诊原因' : ''"
|
||
class="inline-input"
|
||
:disabled="!isEditMode || !scope.row.stopClinic"
|
||
></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作" width="150" fixed="right">
|
||
<template #default="scope">
|
||
<el-button
|
||
type="primary"
|
||
size="small"
|
||
@click="handleAddSchedule(scope.row)"
|
||
:disabled="!isEditMode"
|
||
>
|
||
添加
|
||
</el-button>
|
||
<el-button
|
||
type="danger"
|
||
size="small"
|
||
@click="handleDeleteSchedule(scope.row)"
|
||
:disabled="!isEditMode"
|
||
>
|
||
删除
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部操作按钮 -->
|
||
<div class="bottom-buttons">
|
||
<el-button type="primary" @click="handleSave" :disabled="!isEditMode">确定</el-button>
|
||
<el-button @click="handleCancel">取消</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 号源记录对话框 -->
|
||
<el-dialog
|
||
v-model="recordDialogVisible"
|
||
title="号源记录"
|
||
width="30%"
|
||
:close-on-click-modal="true"
|
||
>
|
||
<div class="appointment-records">
|
||
<div class="record-item" v-for="record in appointmentRecords" :key="record.index">
|
||
<span class="record-time">{{ record.time }}</span>
|
||
</div>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button @click="recordDialogVisible = false">确定</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup name="DoctorSchedule">
|
||
import {computed, onMounted, ref, watch} from 'vue'
|
||
import {useRoute, useRouter} from 'vue-router'
|
||
import {ElDialog, ElMessage, ElMessageBox} from 'element-plus'
|
||
import {View} from '@element-plus/icons-vue'
|
||
import {addDoctorSchedule, addDoctorScheduleWithDate, deleteDoctorSchedule} from '../api'
|
||
|
||
// 路由和导航
|
||
const route = useRoute()
|
||
const router = useRouter()
|
||
|
||
// 筛选参数
|
||
const filterParams = ref({
|
||
orgName: '演示医院',
|
||
deptName: '测试内科',
|
||
startDate: new Date('2025-12-01'),
|
||
appointmentType: '普通'
|
||
})
|
||
|
||
// 医生列表数据
|
||
const doctorOptions = ref({
|
||
'普通': [
|
||
{ label: '张医生', value: '张医生' },
|
||
{ label: '李医生', value: '李医生' },
|
||
{ label: '王医生', value: '王医生' },
|
||
{ label: '赵医生', value: '赵医生' }
|
||
],
|
||
'专家': [
|
||
{ label: '请选择专家', value: '' },
|
||
{ label: '王教授', value: '王教授' },
|
||
{ label: '李主任', value: '李主任' },
|
||
{ label: '赵教授', value: '赵教授' },
|
||
{ label: '张主任', value: '张主任' }
|
||
]
|
||
})
|
||
|
||
// 根据排班类型获取医生选项
|
||
const getDoctorOptions = (appointmentType) => {
|
||
return doctorOptions.value[appointmentType] || doctorOptions.value['普通']
|
||
}
|
||
|
||
// 编辑模式控制
|
||
const isEditMode = computed(() => {
|
||
return route.query.mode === 'edit'
|
||
})
|
||
|
||
// 排班列表数据
|
||
const scheduleList = ref([])
|
||
|
||
// 当前科室信息
|
||
const currentDept = ref(null)
|
||
|
||
// 按日期分组的排班数据
|
||
const groupedSchedule = computed(() => {
|
||
// 按日期分组
|
||
const groups = {}
|
||
|
||
scheduleList.value.forEach(item => {
|
||
if (!groups[item.date]) {
|
||
groups[item.date] = {
|
||
date: item.date,
|
||
weekday: item.weekday,
|
||
items: []
|
||
}
|
||
}
|
||
groups[item.date].items.push(item)
|
||
})
|
||
|
||
// 转换为数组
|
||
return Object.values(groups)
|
||
})
|
||
|
||
// 生成一周排班数据
|
||
const generateWeekSchedule = (startDate) => {
|
||
const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
|
||
const timeSlots = [
|
||
{ label: '上午', startTime: '08:00', endTime: '12:00' },
|
||
{ label: '下午', startTime: '14:30', endTime: '18:00' }
|
||
]
|
||
|
||
const schedule = []
|
||
|
||
// 生成一周7天的数据
|
||
for (let i = 0; i < 7; i++) {
|
||
const currentDate = new Date(startDate)
|
||
currentDate.setDate(startDate.getDate() + i)
|
||
|
||
const dateStr = currentDate.toISOString().split('T')[0]
|
||
const weekday = days[currentDate.getDay()]
|
||
|
||
// 每个时间段生成一条记录
|
||
timeSlots.forEach(slot => {
|
||
schedule.push({
|
||
id: `${dateStr}-${slot.label}`,
|
||
date: dateStr,
|
||
weekday: weekday,
|
||
timeSlot: slot.label,
|
||
startTime: slot.startTime,
|
||
endTime: slot.endTime,
|
||
doctorName: '',
|
||
room: '',
|
||
maxNumber: '',
|
||
appointmentItem: '',
|
||
registrationFee: 0,
|
||
clinicItem: '',
|
||
treatmentFee: 0,
|
||
online: true,
|
||
stopClinic: false,
|
||
stopReason: ''
|
||
})
|
||
})
|
||
}
|
||
|
||
return schedule
|
||
}
|
||
|
||
// 初始化数据
|
||
const initData = () => {
|
||
// 从路由参数获取科室ID
|
||
const deptId = route.query.deptId
|
||
console.log('科室ID:', deptId)
|
||
|
||
// 设置当前科室信息
|
||
if (deptId) {
|
||
currentDept.value = { id: deptId }
|
||
}
|
||
|
||
// 生成排班数据
|
||
scheduleList.value = generateWeekSchedule(filterParams.value.startDate)
|
||
}
|
||
|
||
// 排班类型变化处理
|
||
const handleAppointmentTypeChange = () => {
|
||
// 当排班类型改变时,清空所有排班记录的医生选择
|
||
scheduleList.value.forEach(item => {
|
||
// 如果当前选择的医生不在新类型对应的医生列表中,则清空
|
||
const currentDoctors = getDoctorOptions(filterParams.value.appointmentType)
|
||
const doctorExists = currentDoctors.some(doctor => doctor.value === item.doctorName)
|
||
if (!doctorExists) {
|
||
item.doctorName = ''
|
||
}
|
||
})
|
||
}
|
||
|
||
// 挂号项目变化处理
|
||
const handleAppointmentItemChange = (row) => {
|
||
if (row.appointmentItem) {
|
||
// 从挂号项目中提取费用数字,例如 "挂号费 50" -> 50
|
||
const feeMatch = row.appointmentItem.match(/(\d+)/)
|
||
if (feeMatch) {
|
||
row.registrationFee = parseInt(feeMatch[1])
|
||
} else {
|
||
row.registrationFee = 0
|
||
}
|
||
} else {
|
||
row.registrationFee = 0
|
||
}
|
||
}
|
||
|
||
// 诊查项目变化处理
|
||
const handleClinicItemChange = (row) => {
|
||
// 诊查项目费用映射表
|
||
const clinicFeeMap = {
|
||
'常规诊查': 10,
|
||
'专科诊查': 20,
|
||
'特殊诊查': 30,
|
||
'专家诊查': 50
|
||
}
|
||
|
||
if (row.clinicItem && clinicFeeMap[row.clinicItem]) {
|
||
row.treatmentFee = clinicFeeMap[row.clinicItem]
|
||
} else {
|
||
row.treatmentFee = 0
|
||
}
|
||
}
|
||
|
||
// 添加排班
|
||
const handleAddSchedule = (row) => {
|
||
// 创建新的排班记录,基于当前行的日期和时段
|
||
const newSchedule = {
|
||
id: `new-${Date.now()}-${Math.random()}`,
|
||
date: row.date,
|
||
weekday: row.weekday,
|
||
timeSlot: row.timeSlot,
|
||
startTime: row.startTime || '08:00',
|
||
endTime: row.endTime || '12:00',
|
||
doctorName: '',
|
||
room: '',
|
||
maxNumber: '',
|
||
appointmentItem: '',
|
||
registrationFee: '',
|
||
clinicItem: '',
|
||
treatmentFee: '',
|
||
online: true,
|
||
stopClinic: false,
|
||
stopReason: '',
|
||
isNew: true // 标记为新添加的记录
|
||
}
|
||
|
||
// 找到当前行在列表中的位置,在其后插入新记录
|
||
const currentIndex = scheduleList.value.findIndex(item => item.id === row.id)
|
||
if (currentIndex !== -1) {
|
||
scheduleList.value.splice(currentIndex + 1, 0, newSchedule)
|
||
ElMessage.success('添加排班成功')
|
||
} else {
|
||
// 如果找不到,添加到对应日期组的末尾
|
||
scheduleList.value.push(newSchedule)
|
||
ElMessage.success('添加排班成功')
|
||
}
|
||
}
|
||
|
||
// 删除排班
|
||
const handleDeleteSchedule = (row) => {
|
||
ElMessageBox.confirm('确定要删除这条排班记录吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
// 如果是已保存的记录(有后端ID),调用删除接口
|
||
if (row.backendId && !row.isNew) {
|
||
deleteDoctorSchedule(row.backendId).then(res => {
|
||
if (res.code === 200) {
|
||
// 从列表中移除
|
||
const index = scheduleList.value.findIndex(item => item.id === row.id)
|
||
if (index !== -1) {
|
||
scheduleList.value.splice(index, 1)
|
||
}
|
||
ElMessage.success('删除成功')
|
||
} else {
|
||
ElMessage.error(res.msg || '删除失败')
|
||
}
|
||
}).catch(error => {
|
||
console.error('删除排班失败:', error)
|
||
ElMessage.error('删除失败,请稍后重试')
|
||
})
|
||
} else {
|
||
// 如果是新添加的记录(未保存),直接从列表中移除
|
||
const index = scheduleList.value.findIndex(item => item.id === row.id)
|
||
if (index !== -1) {
|
||
scheduleList.value.splice(index, 1)
|
||
ElMessage.success('删除成功')
|
||
}
|
||
}
|
||
}).catch(() => {
|
||
// 用户取消删除
|
||
})
|
||
}
|
||
|
||
// 号源记录对话框相关
|
||
const recordDialogVisible = ref(false)
|
||
const currentRow = ref(null)
|
||
const appointmentRecords = ref([])
|
||
|
||
// 计算号源记录
|
||
const calculateAppointmentRecords = (row) => {
|
||
const { startTime, endTime, maxNumber } = row
|
||
|
||
// 将时间转换为分钟数
|
||
const [startHour, startMinute] = startTime.split(':').map(Number)
|
||
const [endHour, endMinute] = endTime.split(':').map(Number)
|
||
|
||
const startTotalMinutes = startHour * 60 + startMinute
|
||
const endTotalMinutes = endHour * 60 + endMinute
|
||
|
||
// 计算总时长和间隔
|
||
const totalDuration = endTotalMinutes - startTotalMinutes
|
||
const interval = Math.floor(totalDuration / maxNumber)
|
||
|
||
// 生成号源记录
|
||
const records = []
|
||
for (let i = 0; i < maxNumber; i++) {
|
||
const minutes = startTotalMinutes + i * interval
|
||
const hour = Math.floor(minutes / 60).toString().padStart(2, '0')
|
||
const minute = (minutes % 60).toString().padStart(2, '0')
|
||
records.push({
|
||
index: i + 1,
|
||
time: `${hour}:${minute}`
|
||
})
|
||
}
|
||
|
||
return records
|
||
}
|
||
|
||
// 查看号源记录
|
||
const handleViewRecord = (row) => {
|
||
// 验证开始时间、结束时间和限号数量
|
||
if (!row.startTime || !row.endTime || !row.maxNumber) {
|
||
ElMessageBox.confirm('请先设置开始时间、结束时间和限号数量', '', {
|
||
confirmButtonText: '确定',
|
||
type: 'warning',
|
||
showCancelButton: false
|
||
})
|
||
return
|
||
}
|
||
|
||
// 计算号源记录
|
||
currentRow.value = row
|
||
appointmentRecords.value = calculateAppointmentRecords(row)
|
||
recordDialogVisible.value = true
|
||
}
|
||
|
||
// 保存排班
|
||
const handleSave = async () => {
|
||
try {
|
||
// 验证必填字段
|
||
const invalidSchedules = scheduleList.value.filter(item => {
|
||
// 检查是否有必填字段为空
|
||
return !item.doctorName || !item.room || !item.startTime || !item.endTime || !item.maxNumber
|
||
})
|
||
|
||
if (invalidSchedules.length > 0) {
|
||
ElMessage.warning('请完善所有排班记录的必填信息(医生、诊室、开始时间、结束时间、限号数量)')
|
||
return
|
||
}
|
||
|
||
// 转换数据格式以匹配后端实体,并建立映射关系
|
||
const schedulesToSave = scheduleList.value.map((item, index) => {
|
||
// 解析挂号项目和诊查项目,提取费用
|
||
let registrationFee = 0
|
||
let diagnosisFee = 0
|
||
|
||
if (item.appointmentItem) {
|
||
const feeMatch = item.appointmentItem.match(/(\d+)/)
|
||
if (feeMatch) {
|
||
registrationFee = parseInt(feeMatch[1])
|
||
}
|
||
}
|
||
|
||
if (item.clinicItem) {
|
||
// 这里可以根据诊查项目设置诊疗费,暂时设为0或从其他字段获取
|
||
diagnosisFee = item.treatmentFee ? parseInt(item.treatmentFee) : 0
|
||
}
|
||
|
||
return {
|
||
localIndex: index, // 保存本地索引,用于更新
|
||
localId: item.id, // 保存本地ID
|
||
scheduleData: {
|
||
id: item.backendId || null, // 如果是新记录,id为null
|
||
weekday: item.weekday,
|
||
timePeriod: item.timeSlot,
|
||
doctor: item.doctorName,
|
||
clinic: item.room,
|
||
startTime: item.startTime,
|
||
endTime: item.endTime,
|
||
limitNumber: parseInt(item.maxNumber) || 0,
|
||
registerItem: item.appointmentItem || '',
|
||
registerFee: registrationFee,
|
||
diagnosisItem: item.clinicItem || '',
|
||
diagnosisFee: diagnosisFee,
|
||
isOnline: item.online || false,
|
||
isStopped: item.stopClinic || false,
|
||
stopReason: item.stopClinic ? (item.stopReason || '') : '',
|
||
deptId: currentDept.value?.id || route.query.deptId || null,
|
||
scheduledDate: item.date // 添加具体日期字段
|
||
}
|
||
}
|
||
})
|
||
|
||
// 只保存新添加的记录(isNew: true)或没有backendId的记录
|
||
const newSchedulesToSave = schedulesToSave.filter(({ localIndex }) => {
|
||
const item = scheduleList.value[localIndex]
|
||
return item.isNew || !item.backendId // 只保存新记录或没有backendId的记录
|
||
})
|
||
|
||
if (newSchedulesToSave.length === 0) {
|
||
ElMessage.info('没有需要保存的新排班记录')
|
||
// 返回上一页
|
||
router.back()
|
||
return
|
||
}
|
||
|
||
// 批量保存排班
|
||
let successCount = 0
|
||
let failCount = 0
|
||
const errors = []
|
||
|
||
for (const { localIndex, localId, scheduleData } of newSchedulesToSave) {
|
||
try {
|
||
// 确保新记录的id为null
|
||
scheduleData.id = null
|
||
|
||
// 使用带日期的API,日期信息已包含在scheduleData中
|
||
const res = await addDoctorScheduleWithDate(scheduleData)
|
||
if (res.code === 200 && res.data) {
|
||
successCount++
|
||
// 更新本地记录的backendId
|
||
const localItem = scheduleList.value[localIndex]
|
||
if (localItem) {
|
||
// 从响应中获取保存后的ID
|
||
if (res.data && typeof res.data === 'object' && res.data.id) {
|
||
localItem.backendId = res.data.id
|
||
localItem.isNew = false
|
||
} else if (res.data && typeof res.data === 'number') {
|
||
localItem.backendId = res.data
|
||
localItem.isNew = false
|
||
} else if (res.data === true) {
|
||
// 如果后端返回的是boolean true,标记为已保存
|
||
localItem.isNew = false
|
||
localItem.saved = true
|
||
} else {
|
||
// 其他情况,标记为已保存
|
||
localItem.isNew = false
|
||
}
|
||
}
|
||
} else {
|
||
failCount++
|
||
const errorMsg = res.msg || '保存失败'
|
||
errors.push(errorMsg)
|
||
console.error('保存排班失败:', errorMsg, res)
|
||
}
|
||
} catch (error) {
|
||
failCount++
|
||
const errorMsg = error.message || '保存异常'
|
||
errors.push(errorMsg)
|
||
console.error('保存排班异常:', error)
|
||
}
|
||
}
|
||
|
||
// 如果有错误,显示详细错误信息
|
||
if (errors.length > 0) {
|
||
console.error('保存错误详情:', errors)
|
||
}
|
||
|
||
if (failCount === 0) {
|
||
ElMessage.success(`排班保存成功,共保存 ${successCount} 条记录`)
|
||
// 返回上一页
|
||
router.back()
|
||
} else {
|
||
ElMessage.warning(`部分排班保存失败,成功 ${successCount} 条,失败 ${failCount} 条`)
|
||
if (errors.length > 0) {
|
||
console.error('错误详情:', errors.join('; '))
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('保存排班失败:', error)
|
||
ElMessage.error('保存失败,请稍后重试')
|
||
}
|
||
}
|
||
|
||
// 取消操作
|
||
const handleCancel = () => {
|
||
// 返回上一页
|
||
router.back()
|
||
}
|
||
|
||
// 页面加载时初始化数据
|
||
onMounted(() => {
|
||
initData()
|
||
})
|
||
|
||
// 监听路由参数变化,重新初始化数据
|
||
watch(
|
||
() => [route.query.deptId, route.query.mode],
|
||
() => {
|
||
initData()
|
||
},
|
||
{ deep: true }
|
||
)
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.doctorschedule-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
padding: 20px;
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.doctorschedule-header {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.doctorschedule-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin: 0;
|
||
}
|
||
|
||
.doctorschedule-content {
|
||
background-color: #fff;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.filter-condition {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
gap: 16px;
|
||
}
|
||
|
||
.filter-label {
|
||
font-weight: 500;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.filter-select {
|
||
width: 150px;
|
||
}
|
||
|
||
.filter-date-picker {
|
||
width: 200px;
|
||
}
|
||
|
||
.radio-group {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.schedule-table-container {
|
||
margin-bottom: 20px;
|
||
width: 100%;
|
||
overflow-x: auto;
|
||
}
|
||
|
||
.daily-schedule {
|
||
margin-bottom: 20px;
|
||
border: 1px solid #ebeef5;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
width: 100%;
|
||
}
|
||
|
||
.daily-header {
|
||
background-color: #f5f7fa;
|
||
padding: 10px 15px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.date-text {
|
||
color: #333;
|
||
}
|
||
|
||
.weekday-text {
|
||
color: #606266;
|
||
font-weight: normal;
|
||
}
|
||
|
||
.schedule-table {
|
||
width: 100% !important;
|
||
min-width: 100% !important;
|
||
|
||
:deep(.el-table__header-wrapper) {
|
||
width: 100% !important;
|
||
border-top: none;
|
||
}
|
||
|
||
:deep(.el-table__body-wrapper) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
:deep(.el-table__header-wrapper th.el-table__cell),
|
||
:deep(.el-table__body-wrapper td.el-table__cell) {
|
||
text-align: center;
|
||
padding: 8px 0;
|
||
}
|
||
|
||
/* 确保表格容器填满 */
|
||
:deep(.el-table__inner-wrapper) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
/* 确保表格本身填满 */
|
||
:deep(.el-table__body) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
/* 确保表格列正确分配宽度 */
|
||
:deep(.el-table__header) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
:deep(.el-table__header tr),
|
||
:deep(.el-table__body tr) {
|
||
width: 100% !important;
|
||
}
|
||
|
||
/* 确保表格容器的最小宽度与内容匹配 */
|
||
:deep(.el-table) {
|
||
width: 100% !important;
|
||
min-width: 100% !important;
|
||
}
|
||
}
|
||
|
||
.inline-select {
|
||
width: 100%;
|
||
}
|
||
|
||
.inline-input {
|
||
width: 100%;
|
||
}
|
||
|
||
.time-picker {
|
||
width: 100%;
|
||
}
|
||
|
||
.record-icon {
|
||
font-size: 18px;
|
||
color: #409eff;
|
||
cursor: pointer;
|
||
transition: color 0.2s;
|
||
}
|
||
|
||
.record-icon:hover {
|
||
color: #66b1ff;
|
||
}
|
||
|
||
.bottom-buttons {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 16px;
|
||
}
|
||
|
||
/* 号源记录对话框样式 */
|
||
.appointment-records {
|
||
max-height: 300px;
|
||
overflow-y: auto;
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.record-item {
|
||
padding: 8px 0;
|
||
border-bottom: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.record-item:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.record-time {
|
||
font-size: 16px;
|
||
color: #333;
|
||
}
|
||
|
||
.dialog-footer {
|
||
text-align: center;
|
||
}
|
||
|
||
/* 隐藏数字输入框的增减按钮 */
|
||
:deep(.el-input__inner[type="number"]) {
|
||
appearance: textfield;
|
||
-moz-appearance: textfield;
|
||
}
|
||
:deep(.el-input__inner[type="number"])::-webkit-outer-spin-button,
|
||
:deep(.el-input__inner[type="number"])::-webkit-inner-spin-button {
|
||
appearance: none;
|
||
-webkit-appearance: none;
|
||
margin: 0;
|
||
}
|
||
</style> |