实现效果
业务需求:
1.查看当前人员每个月的排班信息
2.通过二次弹窗调整排班
主要实现方法:
1.需要根据后端返回数据渲染面板,eleui没有提供方法,需要自己手动更新面板,这里我是通过getCurTime(获取当前面板月份)和resetHtml(配合v-if重新渲染)实现的。
2.月份只显示当月,通过样式把不是当月的隐藏掉
完整代码:vue3+ts
1.弹窗代码
<template>
<!-- 弹窗 -->
<el-dialog v-model="props.dialogVisible" v-if="props.dialogVisible" width="60%" @close="cancel"
:close-on-click-modal="false">
<!-- 标题 -->
<template #header>
<div class="report-title">
<span>查看排班</span>
</div>
</template>
<!-- 日历面板 -->
<el-calendar ref="calendar" v-model="data.value" class="calendar-box">
<!-- 头部 -->
<template #header="{ date }">
<div class="calendar-title">
<el-button size="small" @click="selectDate('prev-month')">
上个月
</el-button>
<span>{{ getCurTime(date) }}</span>
<el-button size="small" @click="selectDate('next-month')">
下个月
</el-button>
</div>
</template>
<!-- 主要区域 -->
<template #date-cell="{ data }" v-if="data.resetHtml">
<!-- 自定义格式显示日期01-31 -->
<p>{{ data.day.split('-').slice(2).join('-') }}</p>
<!-- 当前账号 -->
<p>{{ getCurAccount(data.day) }}</p>
<el-button :disabled="disabledHandle(data)" link size="small"
@click="editSchedule(getCurAccount(data.day), data)">
编辑排班
</el-button>
</template>
</el-calendar>
<!--编辑排班弹窗 -->
<el-dialog class="modify-box" v-model="data.innerVisible" append-to-body width="500" title="编辑排班" @close="cancelInner">
<el-form :model="data.formData" ref="formRef" :rules="data.rules" label-width="130px" label-suffix=":">
<el-form-item label="账号" prop="userOmsAccount">
<el-select class="select-box" v-model="data.formData.userOmsAccount" placeholder="请选择" style="width: 100%;"
:disabled="props.dialogItem.type === 'view'">
<el-option v-for="item in data.accounList" :label="item.username" :value="item.userId" />
</el-select>
</el-form-item>
<el-form-item label="调整排班" prop="workingStatus">
<el-switch active-text="上班" inactive-text="下班" :active-value="1" :inactive-value="0"
v-model="data.formData.workingStatus" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="cancelInner">返 回</el-button>
<el-button type="primary" @click="submitInner(formRef)">保 存</el-button>
</span>
</template>
</el-dialog>
</el-dialog>
</template>
<script lang="ts" setup>
import { ElMessage } from 'element-plus'
import { filterDate } from '@/utils/filter';
import { useRoute } from 'vue-router'
import { reactive, onMounted, watch, ref, computed } from 'vue'
import { getScheduleInfo, getAccounListApi, updateScheduleInfo } from '@/api/taskConfig'
import type { CalendarDateType, CalendarInstance } from 'element-plus'
const calendar = ref<CalendarInstance>()
const formRef = ref(null);
const route = useRoute()
const props = defineProps({
dialogVisible: { // 表格数据
type: Boolean,
default: false
},
dialogItem: {
type: Object,
default: () => { }
}
})
const data = reactive({
resetHtml: false,//面板区域重新渲染标识
accounList: [],
formData: {} as any,
innerVisible: false,
scheduleList: [],
curTime: '',
value: new Date(),
rules: {
userOmsAccount: [
{
required: true,
message: '请选择',
trigger: ['blur', 'change'],
},
],
}
})
onMounted(() => {
})
watch(() => props.dialogVisible, (newVal) => {
if (newVal) {
getAccounList()
}
})
const emit = defineEmits(['submit'])
const getAccounList = async () => {
let res: any = await getAccounListApi(route.query.id)
if (res && res.data.code === "200") {
data.accounList = res.data.data.centerUserList
}
}
const save = async () => {
let params = {
...data.formData,
userOmsAccount: data.accounList.find((item: any) => item.userId === data.formData.userOmsAccount)?.username || ''
}
let res: any = await updateScheduleInfo(params)
if (res && res.data.code === "200") {
ElMessage.success('编辑排班成功')
data.innerVisible = false
initData()
}
}
const submitInner = (formEl: any | undefined) => {
if (!formEl) return
formEl.validate((valid: any) => {
if (valid) {
save()
} else {
return false
}
})
}
const cancelInner = () => {
data.innerVisible = false
}
const editSchedule = (val: any, time: any) => {
// 当前账户信息
let accountObj: any = data.accounList.find((item: any) => item.username === val)
data.formData.workingDate = time.day
data.formData.reportInterpretCenterId = route.query.id
data.formData.temporaryId = props.dialogItem.temporaryId
if (accountObj) {
data.formData.userOmsAccount = accountObj.userId
data.formData.workingStatus = 1
} else {
data.formData.userOmsAccount = ''
data.formData.workingStatus = 1
}
data.innerVisible = true
}
const disabledHandle = (date: any) => {
// 当天禁止
let curDate = filterDate(new Date())
if (curDate === date.day) {
return true
} else {
return false
}
}
const getCurAccount = (date: any) => {
if (data.scheduleList.length) {
let userOmsAccountObj: any = data.scheduleList.find((item: any) => item.workingDate === date)
if (userOmsAccountObj) {
return userOmsAccountObj.userOmsAccount
} else {
return ''
}
}
}
// 根据当前显示月份 获取面板数据
const getCurTime = (date: any) => {
if (data.curTime !== date) {
data.curTime = date
initData()
}
return date
}
const selectDate = (val: CalendarDateType) => {
if (!calendar.value) return
calendar.value.selectDate(val)
}
const initData = async () => {
data.resetHtml = false
let params = {
monthYear: formatMonthYear(data.curTime),
reportInterpretCenterId: route.query.id,
temporaryId: props.dialogItem.temporaryId,
}
let res: any = await getScheduleInfo(params)
if (res && res.data.code === "200") {
data.scheduleList = res.data.data
data.resetHtml = true
}
}
// 2025 年 4 月转换为2025-04
const formatMonthYear = (dateStr: string): string => {
const date = dateStr.split(' ');
const formattedMonth = date[2].padStart(2, '0'); // 确保月份是两位数
return `${date[0]}-${formattedMonth}`;
}
const cancel = () => {
resetForm()
emit('submit')
}
// 重置弹窗数据
const resetForm = () => {
data.resetHtml = false
data.curTime = ''
data.scheduleList = []
data.value = new Date()
}
</script>
<style lang="scss" scoped>
::v-deep(.el-calendar-table td.is-today) {
color: rgb(221, 96, 7);
// color: rgb(51, 255, 102);
}
.edit-btn {
padding: 5px 0;
}
// 非本月数据不显示
::v-deep .el-calendar-table:not(.is-range) td.prev,
::v-deep .el-calendar-table:not(.is-range) td.next {
cursor: not-allowed;
pointer-events: none;
}
.prev>.el-calendar-day>p {
display: none;
}
.prev>.el-calendar-day>button {
display: none;
}
.next>.el-calendar-day>p {
display: none;
}
.next>.el-calendar-day>button {
display: none;
}
.calendar-title {
width: 100%;
display: flex;
justify-content: space-between;
}
.el-button--primary {
background: #ff8833 !important;
}
</style>
2.使用弹窗
html,ts
<el-button link type="primary" @click="openDialog(scope.row, 'dialogVisibleView')">
查看排班
</el-button>
<!-- 查看排班弹窗 -->
<ViewDialog :dialogVisible="data.dialogVisibleView" :dialogItem="data.dialogItem"
@cancel="cancel('dialogVisibleView')" @submit="submit('dialogVisibleView')">
</ViewDialog>
import ViewDialog from './components/ViewDialog.vue';
const data = reactive({
dialogVisibleView: false,
dialogItem: {} as any,
})
//间隔...
const openDialog = (val: Object, type: string) => {
data.dialogItem = val
data[type] = true
}
const cancel = (type: string) => {
data[type] = false
}
const submit = (type: string) => {
data[type] = false
// data.pageData.pageNum = 1
// searchHandle()
}