公司物流部要个简易的排班功能,由主管去设置线路,线路绑定上负责人。然后直接往日历里添加。
1、隐藏了自带的切换月份,改用了日期选择器。
2、禁用了非本月的点击事件,防止点击自动跳转到其他月份。
3、添加了点击多选,批量处理,也有单日排班处理。
4、拖拽删除排班,
代码如下
export function getFirstDay(monthValue) {
let date = new Date(monthValue)
let month = parseInt(date.getMonth() + 1)
let day = date.setDate(1);
if (month < 10) month = '0' + month
if (day < 10) day = '0' + day
return date.getFullYear() + '-' + month
}
export function getLastDay(monthValue){
var year = new Date(monthValue).getFullYear(); //获取年份
var month = new Date(monthValue).getMonth() + 1; //获取月份
var lastDate = new Date(year, month , 0).getDate(); //获取当月最后一日
month = month < 10 ? '0' + month : month ; //月份补 0
return [ year,month ,lastDate ].join("-")
}
export function getNextDayByDay(dayValue) {
let date = new Date(new Date(dayValue).getTime() + 3600 * 24 * 1000)
let month = parseInt(date.getMonth() + 1)
let day = date.getDate()
if (month < 10) month = '0' + month
if (day < 10) day = '0' + day
return date.getFullYear() + '-' + month + '-' + day
}
时间过滤是因为我这边大部分后端接口让传2个日期,所以统一处理了。
<template>
<div class="calender_body">
<div class="calender-class">
<div class="class-header">
<el-date-picker
v-model="currentMonth"
type="month"
format="yyyy 年 MM 月"
value-format="yyyy-MM"
placeholder="选择月份"
@change="changeCurrentMonth"
/>
<el-button
type="primary"
style="margin-left: 10px;"
:disabled="!selectDateItems.length"
@click="handleShowAddBatchDialog"
>批量排班</el-button>
</div>
<div class="monthText">{{ currentMonth && currentMonth.replace(/-/,'年') }}月 排班表</div>
<div v-if="isdraging" class="deleteDiv">
<div
class="delIconBox"
@dragover.prevent
@dragenter.prevent
@drop="handleDeleteClassByDrop"
>
<i class="el-icon-delete" style="font-size: 40px;" />
</div>
</div>
</div>
<el-calendar v-model="currentMonth">
<!-- 这里使用的是 2.5 slot 语法,对于新项目请使用 2.6 slot 语法-->
<template slot="dateCell" slot-scope="{date, data}">
<div
class="day-content-class"
:class="selectDateItems.some(el => el == data.day)? 'is-selected':''"
@click.stop="handleSelectItem(data)"
>
<div class="header-class">
<div class="day-class">{{ data.day.split('-').slice(1).join('-') }}</div>
<div class="handle-class">
<el-button
icon="el-icon-edit"
class="edit-color"
circle
@click.stop="handleWorkInfo(data)"
/>
</div>
</div>
<template v-if="viewDate[data.day]">
<div class="paiban-class">
<!-- @dragenter="handleDragEnter($event, dayValue)" @dragover.prevent="handleDragOver($event)"-->
<div
v-for="(dayValue, i,index) in viewDate[data.day]"
:key="index"
draggable="true"
@dragstart="handleDragStart(dayValue)"
@dragend="handleDragEnd()"
>
<div class="class-item-tag">
<span>{{ dayValue.logisticsRouteName }}</span>
<span v-if="dayValue.users">-{{ dayValue.users[0].userName }}</span>
</div>
</div>
</div>
</template>
<template v-else>
<div class="no-work-class">
<div class="icon-class">
<i class="el-icon-date" />
</div>
<div class="tips-class">暂无排班</div>
</div>
</template>
</div>
</template>
</el-calendar>
<!-- 批量排班 -->
<el-dialog title="批量排班" :visible.sync="addBatchDialog" size="50%">
<el-form :model="addBatchForm">
<el-form-item label="值班路线" label-width="80px">
<el-select
v-model="addBatchForm.logisticsRouteCode"
style="width:100%"
placeholder="请选择"
filterable
multiple
default-first-option
clearable
>
<el-option
v-for="item in routerDataList"
:key="item.id"
:label="item.name"
:value="item.code"
:disabled="selectDateItemsHasRouteArr.some(el => el == item.code)"
>
<span style="float: left">{{ item.name }}</span>
<span
style="float: right;margin-right: 12px; color: #8492a6; font-size: 13px"
>{{ item.userInfos[0].userName }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addBatchDialog = false">取 消</el-button>
<el-button type="primary" @click="handleSubmitAddBatch">确 定</el-button>
</span>
</el-dialog>
<!-- 排班详情-->
<el-drawer :title="'【' + currentDay + '】排班'" :visible.sync="dayClassdrawer" size="50%">
<div style="width: 99%;margin:0 auto">
<el-button type="primary" style="margin-bottom: 4px;" @click="addDayClassDialog = true">添加排班</el-button>
<el-table :data="workInfoList" border :height="`calc(100vh - 180px)`">
<el-table-column prop="day" label="日期" width="90" show-overflow-tooltip />
<el-table-column prop="logisticsRouteName" label="线路" width="140" show-overflow-tooltip />
<el-table-column label="负责人" width="120" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.users.join('; ') }}</template>
</el-table-column>
<el-table-column label="途径医院" width="*" show-overflow-tooltip>
<template slot-scope="scope">{{ scope.row.hospitals.join('; ') }}</template>
</el-table-column>
<el-table-column fixed="right" label="操作" width="100">
<template slot-scope="scope">
<el-button
type="text"
style="color:red"
@click.native.prevent="deleteRow(scope.row)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-drawer>
<!-- 单日排班 -->
<el-dialog :title="'添加【' + currentDay + '】排班'" :visible.sync="addDayClassDialog" size="50%">
<el-form :model="addForm">
<el-form-item label="值班路线" label-width="80px">
<el-select
v-model="addForm.logisticsRouteCode"
style="width:100%"
placeholder="请选择"
filterable
multiple
default-first-option
clearable
>
<el-option
v-for="item in routerDataList"
:key="item.id"
:label="item.name"
:value="item.code"
:disabled="workInfoList.some(el => el.logisticsRouteCode == item.code)"
>
<span style="float: left">{{ item.name }}</span>
<span
style="float: right;margin-right: 12px; color: #8492a6; font-size: 13px"
>{{ item.userInfos[0].userName }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addDayClassDialog = false">取 消</el-button>
<el-button type="primary" @click="handleSubmitAddDayClass">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { getFirstDay, getNextDayByDay, getLastDay } from "@/utils/index";
export default {
data() {
return {
isdraging: false,
selectDateItems: [], // 当前选择日期
selectDateItemsHasRouteArr: [], // 当前日期包含的线路
routerDataList: [], // 线路
currentMonth: "",
viewDate: {},
thisDay: null,
thisDayWork: null,
ending: null,
dragging: null,
addBatchDialog: false,
// 批量添加
addBatchForm: {
logisticsRouteCode: []
},
// 单日添加
addForm: {
logisticsRouteCode: []
},
dayClassdrawer: false,
currentDay: "",
addDayClassDialog: false,
workInfoList: [],
dialogLoading: false
};
},
mounted() {
this.getRouteListData();
this.currentMonth = getFirstDay(new Date().getTime());
this.getCurrentMonthClass();
},
methods: {
handleDragStart(item) {
this.isdraging = true;
this.dragging = item;
},
handleDragEnd() {
this.isdraging = false;
},
// 拖动删除排班
handleDeleteClassByDrop(e) {
let params = [this.dragging.id];
this.$api.LogisticsScheduleApi.DeleteLogisticsSchedule(params).then(
res => {
this.$message.success("删除成功");
this.getCurrentMonthClass();
}
);
},
// handleDragOver(e) {
// // 首先把div变成可以放置的元素,即重写dragenter/dragover
// e.dataTransfer.dropEffect = "move"; // e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
// },
// handleDragEnter(e, item) {
// e.dataTransfer.effectAllowed = "move"; // 为需要移动的元素设置dragstart事件
// this.ending = item;
// },
// 获取线路列表
getRouteListData() {
let params = {
pageIndex: 1,
pageSize: 999
};
this.$api.LogisticsScheduleApi.PageLogisticsRoute(params).then(res => {
this.routerDataList = res.data.items;
});
},
// 切换月份
changeCurrentMonth(e) {
this.currentMonth = e;
this.getCurrentMonthClass();
},
// 获取当前月物流排班
getCurrentMonthClass() {
let params = {
StartDay: this.currentMonth + "-01",
EndDay: getLastDay(this.currentMonth + "-01")
};
this.$api.LogisticsScheduleApi.QueryLogisticsSchedule(params).then(
res => {
let obj = {};
if (res.data.length) {
for (let i of res.data) {
if (obj[i.day]) {
obj[i.day].push({ ...i });
} else {
obj[i.day] = [{ ...i }];
}
}
}
this.viewDate = obj;
}
);
},
// 单日排班详情抽屉
handleWorkInfo(data) {
this.currentDay = data.day;
let params = {
StartDay: this.currentDay,
EndDay: getNextDayByDay(this.currentDay)
};
this.$api.LogisticsScheduleApi.QueryLogisticsSchedule(params).then(
res => {
this.workInfoList = res.data.map(el => {
el.hospitals = el.hospitals.map(item => item.hospitalName);
el.users = el.users.map(item => item.userName);
return el;
});
}
);
this.dayClassdrawer = true;
},
// 添加单日排班
handleSubmitAddDayClass() {
let params = {
logisticsRouteCode: this.addForm.logisticsRouteCode,
day: [this.currentDay]
};
this.dialogLoading = true;
this.$api.LogisticsScheduleApi.CreateLogisticsSchedule(params)
.then(res => {
this.$message.success("添加成功");
let parmas = {
day: this.currentDay
};
this.handleWorkInfo(parmas);
this.getCurrentMonthClass();
this.addDayClassDialog = false;
})
.finally(() => {
this.dialogLoading = false;
});
},
// 删除排班
deleteRow(row) {
this.$confirm("此操作将会删除此条排班记录, 是否继续?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
let params = [row.id];
this.$api.LogisticsScheduleApi.DeleteLogisticsSchedule(params).then(
res => {
this.$message.success("删除成功");
this.getCurrentMonthClass();
let date = {
day: this.currentDay
};
this.handleWorkInfo(date);
}
);
});
},
// 选中事件
handleSelectItem(data) {
let dataStr = data.day;
if (this.selectDateItems.findIndex(el => el == dataStr) > -1) {
this.selectDateItems.splice(
this.selectDateItems.findIndex(el => el == dataStr),
1
);
} else {
this.selectDateItems.push(dataStr);
}
},
//批量弹窗
handleShowAddBatchDialog() {
let arr = [];
for (let i of this.selectDateItems) {
if (this.viewDate[i]) {
for (let j of this.viewDate[i]) {
arr.push(j.logisticsRouteCode);
}
}
}
const newArr = [...new Set(arr)];
this.selectDateItemsHasRouteArr = newArr;
this.addBatchDialog = true;
},
//批量排班提交
handleSubmitAddBatch() {
let params = {
logisticsRouteCode: this.addBatchForm.logisticsRouteCode,
day: this.selectDateItems
};
this.dialogLoading = true;
this.$api.LogisticsScheduleApi.CreateLogisticsSchedule(params)
.then(res => {
this.$message.success("添加成功");
this.getCurrentMonthClass();
this.selectDateItems = [];
this.addBatchForm = this.$options.data().addBatchForm;
this.addBatchDialog = false;
})
.finally(() => {
this.dialogLoading = false;
});
}
}
};
</script>
<style lang="scss" scoped>
.calender_body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
.el-table__fixed-right {
height: 100% !important;
}
.calender-class {
position: relative;
width: 100%;
height: 70px;
}
.class-header {
position: relative;
padding: 10px;
display: flex;
}
.deleteDiv {
position: absolute;
width: 100%;
height: 70px;
line-height: 70px;
text-align: center;
z-index: 11;
top: 0;
left: 0;
background: rgba(155, 155, 155, 0.6);
}
.delIconBox {
width: 160px;
height: 60px;
border-radius: 10px;
background: rgba(155, 155, 155, 0.9);
box-shadow: 0 0 10px #fff;
margin: 5px auto;
}
.monthText {
width: 100%;
text-align: center;
font-size: 16px;
font-weight: 500;
line-height: 20px;
color: #666;
height: 20px;
}
::v-deep .el-calendar-table thead th {
box-shadow: inset 0 0 2px rgba(0, 0, 0, 0.3);
}
.is-selected {
color: #1989fa;
background: #ddeffb;
}
::v-deep .el-calendar__body {
height: 85vh;
}
::v-deep .el-calendar-table {
width: 100%;
height: 100%;
//使不是本月的日期不可点击,不会跳转到其他月份
&:not(.is-range) {
td.next {
pointer-events: none;
}
td.prev {
pointer-events: none;
}
}
td.is-selected {
background: none !important;
}
.prev,
.next {
.icon-class,
.tips-class,
.edit-color {
color: #e1e1e1;
}
}
td.is-today {
.day-class {
background: #44a2f3;
width: 50px;
text-align: center;
height: 20px;
border-radius: 4px;
color: #fff;
font-weight: 500;
}
}
}
::v-deep .el-calendar-day {
height: 100% !important;
padding: 1px;
}
::v-deep .el-calendar__header {
display: none;
}
.day-content-class {
height: 100%;
display: flex;
flex-direction: column;
padding: 7px;
}
.header-class {
display: flex;
height: 24px;
justify-content: space-between;
align-items: center;
}
.paiban-class {
display: flex;
flex-flow: wrap;
align-items: center;
.class-item-tag {
font-size: 12px;
line-height: 20px;
color: #fff;
width: auto;
border-radius: 4px;
padding: 0 4px;
margin: 4px;
background: #11be11;
}
}
.paiban-icon-class {
font-size: 22px;
margin: 8px 0 10px 0;
}
.paiban-name-class {
padding-top: 10px;
}
.no-work-class {
text-align: center;
color: #cacaca;
}
.icon-class {
font-size: 20px;
color: #777;
margin-bottom: 20px;
}
.tips-class {
font-size: 14px;
color: #777;
}
.edit-color {
color: #333;
}
</style>
文章参考: https://blog.csdn.net/qq_40601005/article/details/131376086