zhousq
7 months ago
1 changed files with 641 additions and 0 deletions
@ -0,0 +1,641 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<div class="calender-class"> |
|||
<div class="batch-add-Work-class"> |
|||
<el-button class="add-btn-class" size="small" type="primary" @click="batchAddDrawer = true">批量排班</el-button> |
|||
</div> |
|||
<el-calendar ref="calendarMain"> |
|||
<template #date-cell="{ data }"> |
|||
<template v-if="viewDate[data.day.replace(/-/g, '')]"> |
|||
<div class="header-class"> |
|||
<div class="day-class"> |
|||
{{ data.day.split('-').slice(1).join('-') }} |
|||
</div> |
|||
<div class="handle-class"> |
|||
<el-button |
|||
size="mini" |
|||
circle |
|||
@click="handleWorkInfo(viewDate[data.day.replace(/-/g, '')], data)" |
|||
><Icon icon="ep:edit" /> |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
<div class="paiban-class"> |
|||
<div |
|||
v-for="(dayValue, i) in viewDate[data.day.replace(/-/g, '')]" |
|||
:key="i" |
|||
:class="['draggable-div' + i, 'each-paiban-class', setWorkClass(dayValue.sort)]" |
|||
draggable="true" |
|||
@dragstart="handleDragStart(dayValue, data.day)" |
|||
@dragover.prevent="handleDragOver($event)" |
|||
@dragenter="handleDragEnter($event, dayValue)" |
|||
@dragend="handleDragEnd" |
|||
> |
|||
<i> <Icon :icon="setIconClass(dayValue.shiftName)" /></i> |
|||
<div class="paiban-name-class">{{ dayValue.groupName }}</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<template v-else> |
|||
<div class="header-class"> |
|||
<div class="day-class"> |
|||
{{ data.day.split('-').slice(1).join('-') }} |
|||
</div> |
|||
<div class="handle-class"> |
|||
<el-button |
|||
size="mini" |
|||
circle |
|||
@click="handleWorkInfo(viewDate[data.day.replace(/-/g, '')], data)" |
|||
><Icon icon="ep:edit" /> |
|||
</el-button> |
|||
</div> |
|||
</div> |
|||
<div class="no-work-class"> |
|||
<div class="icon-class"><Icon icon="ep:clock" /></div> |
|||
<div class="tips-class"> 暂无排班 </div> |
|||
</div> |
|||
</template> |
|||
</template> |
|||
</el-calendar> |
|||
</div> |
|||
<!-- 批量排班抽屉弹窗 --> |
|||
<div> |
|||
<el-drawer title="批量排班" v-model="batchAddDrawer" size="40%"> |
|||
<div class="demo-drawer_content"> |
|||
<el-form v-model="batchAddForm"> |
|||
<el-form-item label="排班日期" label-width="80px"> |
|||
<el-date-picker |
|||
v-model="batchAddForm.batchDate" |
|||
value-format="YYYY-MM-DD" |
|||
type="daterange" |
|||
range-separator="至" |
|||
start-placeholder="开始日期" |
|||
end-placeholder="结束日期" |
|||
> |
|||
</el-date-picker> |
|||
</el-form-item> |
|||
<el-button type="primary" @click="addDomain" link> <Icon icon="ep:plus" /> </el-button> |
|||
<el-form-item |
|||
label-width="80px" |
|||
v-for="(data, index) in batchAddForm.classData" |
|||
:label="'排班' + (index + 1) + ':'" |
|||
:key="data.key" |
|||
> |
|||
<p></p> |
|||
<span>班次:</span> |
|||
<el-radio-group v-model="data.shiftName"> |
|||
<el-radio label="早">早</el-radio> |
|||
<el-radio label="中">中</el-radio> |
|||
<el-radio label="晚">晚</el-radio> |
|||
</el-radio-group> |
|||
<p></p> |
|||
<span>班别:</span> |
|||
<el-radio-group class="margin-left:80px" v-model="data.groupName"> |
|||
<el-radio label="甲">甲</el-radio> |
|||
<el-radio label="乙">乙</el-radio> |
|||
<el-radio label="丙">丙</el-radio> |
|||
</el-radio-group> |
|||
<el-button @click.prevent="removeDomain(data)" type="danger" size="mini" link |
|||
><Icon icon="ep:delete" |
|||
/></el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
<div class="demo-drawer__footer"> |
|||
<el-button @click="handleBatchClose">取 消</el-button> |
|||
<el-button type="primary" @click="batchAddWork"> 确定 </el-button> |
|||
</div> |
|||
</el-drawer> |
|||
</div> |
|||
<!-- 单独排班 --> |
|||
<div> |
|||
<el-drawer :title="'【' + hanleDay.day + '】排班'" v-model="drawer" size="40%"> |
|||
<div class="add-work-class"> |
|||
<el-button type="primary" @click="innerDrawer = true">添加</el-button> |
|||
<el-drawer |
|||
title="添加排班" |
|||
:append-to-body="true" |
|||
:before-close="handleClose" |
|||
v-model="innerDrawer" |
|||
> |
|||
<div class="demo-drawer__content"> |
|||
<el-form v-model="addForm"> |
|||
<el-form-item label="班次:" label-width="80px"> |
|||
<el-radio-group v-model="addForm.shiftName"> |
|||
<el-radio label="早">早</el-radio> |
|||
<el-radio label="中">中</el-radio> |
|||
<el-radio label="晚">晚</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="班别:" label-width="80px"> |
|||
<el-radio-group v-model="addForm.groupName"> |
|||
<el-radio label="甲">甲</el-radio> |
|||
<el-radio label="乙">乙</el-radio> |
|||
<el-radio label="丙">丙</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
<div class="demo-drawer__footer"> |
|||
<el-button @click="handleClose">取 消</el-button> |
|||
<el-button type="primary" @click="addWork"> 确定 </el-button> |
|||
</div> |
|||
</el-drawer> |
|||
</div> |
|||
<el-table :data="workInfoList"> |
|||
<el-table-column property="date" label="日期" width="100"></el-table-column> |
|||
<el-table-column property="shiftName" label="班次"></el-table-column> |
|||
<el-table-column property="groupName" label="班别"></el-table-column> |
|||
<el-table-column property="startTime" label="开始时间" width="160"></el-table-column> |
|||
<el-table-column property="endTime" label="结束时间" width="160"></el-table-column> |
|||
<el-table-column fixed="right" label="操作" width="120"> |
|||
<template #default="scope"> |
|||
<el-button @click="deleteRow(scope.row, workInfoList)" type="text" size="small"> |
|||
移除 |
|||
</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</el-drawer> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import dayjs from 'dayjs' |
|||
import { ref, reactive, toRefs, watch, computed, onMounted, onBeforeMount, nextTick } from 'vue' |
|||
const message = useMessage() // 消息弹窗 |
|||
const viewDate = ref({ |
|||
'20240417': [ |
|||
{ |
|||
id: '2024-4-17' + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: '早', |
|||
groupName: '甲', |
|||
startTime: '2024-4-17 08:30', |
|||
endTime: '2024-4-17 20:30', |
|||
isNotHoliday: 0, |
|||
classId: 1, |
|||
date: '2024-4-17', |
|||
sort: 1 |
|||
}, |
|||
{ |
|||
id: '2024-4-17' + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: '中', |
|||
groupName: '乙', |
|||
startTime: '2024-4-17 20:30', |
|||
endTime: '2023-4-16 08:30', |
|||
isNotHoliday: 0, |
|||
classId: 1, |
|||
date: '2024-4-17', |
|||
sort: 2 |
|||
} |
|||
], |
|||
'20240416': [ |
|||
{ |
|||
id: '2024-4-16' + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: '早', |
|||
groupName: '甲', |
|||
startTime: '2024-4-16 08:30', |
|||
endTime: '2024-4-16 20:30', |
|||
isNotHoliday: 0, |
|||
classId: 1, |
|||
date: '2024-4-16', |
|||
sort: 1 |
|||
}, |
|||
{ |
|||
id: '2024-4-16' + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: '中', |
|||
groupName: '乙', |
|||
startTime: '2024-4-16 08:30', |
|||
endTime: '2024-4-16 20:30', |
|||
isNotHoliday: 0, |
|||
classId: 1, |
|||
date: '2024-4-16', |
|||
sort: 2 |
|||
}, |
|||
{ |
|||
id: '2024-4-16' + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: '晚', |
|||
groupName: '丙', |
|||
startTime: '2024-4-16 08:30', |
|||
endTime: '2024-10-09 20:30', |
|||
isNotHoliday: 1, |
|||
classId: 1, |
|||
date: '2024-4-16', |
|||
sort: 3 |
|||
} |
|||
] |
|||
}) |
|||
const thisDay = ref() |
|||
const thisDayWork = ref() |
|||
const ending = ref() |
|||
const dragging = ref() |
|||
const batchAddDrawer = ref(false) |
|||
// 批量添加 |
|||
const batchAddForm = ref({ |
|||
batchDate: [], |
|||
classData: [ |
|||
{ |
|||
shiftName: '早', |
|||
groupName: '甲' |
|||
} |
|||
] |
|||
}) |
|||
// 单日添加 |
|||
const addForm = ref({ |
|||
shiftName: '早', |
|||
groupName: '甲', |
|||
sort: 1 |
|||
}) |
|||
const drawer = ref(false) |
|||
const innerDrawer = ref(false) |
|||
const hanleDay = ref('') |
|||
const workInfoList = ref() |
|||
// 时间范围 |
|||
const dateRange = ref({ |
|||
start: '2023-10-1', |
|||
end: '2023-10-20' |
|||
}) |
|||
const changeDateDrawer = ref(false) |
|||
// 点击月中已选中的日期 |
|||
const currentDate = ref([]) |
|||
|
|||
watch( |
|||
() => addForm.value.shiftName, |
|||
(newVal) => { |
|||
switch (newVal) { |
|||
case '早': |
|||
addForm.value.sort = 1 |
|||
break |
|||
case '中': |
|||
addForm.value.sort = 2 |
|||
break |
|||
case '晚': |
|||
addForm.value.sort = 3 |
|||
break |
|||
default: |
|||
break |
|||
} |
|||
} |
|||
) |
|||
const handleDragStart = (item, data) => { |
|||
dragging.value = item |
|||
thisDay.value = data |
|||
let dkey = dayjs(thisDay.value.date).format('YYYYMMDD') |
|||
thisDayWork.value = viewDate.value[dkey] |
|||
} |
|||
const handleDragEnd = () => { |
|||
if (ending.value.id === dragging.value.id) { |
|||
return |
|||
} |
|||
let newItems = [...thisDayWork.value] |
|||
const src = newItems.indexOf(dragging.value) |
|||
const dst = newItems.indexOf(ending.value) |
|||
newItems.splice(src, 1, ...newItems.splice(dst, 1, newItems[src])) |
|||
//obj.set(viewDate.value, thisDay.value, newItems); |
|||
nextTick(() => { |
|||
dragging.value = null |
|||
ending.value = null |
|||
}) |
|||
//let dkey=dayjs(thisDay.value.date).format("YYYYMMDD"); |
|||
//viewDate.value[dkey]=newItems |
|||
// console.log( |
|||
// "🚀 ~ file: App.vue:286 ~ handleDragEnd ~ this.viewDate:", |
|||
// //viewDate.value[dkey] |
|||
// ); |
|||
} |
|||
const handleDragOver = (e) => { |
|||
// 首先把div变成可以放置的元素,即重写dragenter/dragover |
|||
e.dataTransfer.dropEffect = 'move' // e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置! |
|||
} |
|||
const handleDragEnter = (e, item) => { |
|||
e.dataTransfer.effectAllowed = 'move' // 为需要移动的元素设置dragstart事件 |
|||
ending.value = item |
|||
} |
|||
// 获取时间范围中的所有日期 |
|||
const enumerateDaysBetweenDates = (startDate, endDate) => { |
|||
let daysList = [] |
|||
let SDate = dayjs(startDate) |
|||
let EDate = dayjs(endDate) |
|||
//daysList.push(SDate.format("YYYY-MM-DD")); |
|||
while (SDate.isBefore(EDate)) { |
|||
daysList.push(SDate.format('YYYY-MM-DD')) |
|||
//console.log('3333',SDate); |
|||
SDate = SDate.add(1, 'day') |
|||
//console.log('44',SDate); |
|||
} |
|||
daysList.push(EDate.format('YYYY-MM-DD')) |
|||
return daysList |
|||
} |
|||
const setSortValue = (value) => { |
|||
let sort = 1 |
|||
switch (value) { |
|||
case '早': |
|||
sort = 1 |
|||
break |
|||
case '中': |
|||
sort = 2 |
|||
break |
|||
case '晚': |
|||
sort = 3 |
|||
break |
|||
default: |
|||
break |
|||
} |
|||
return sort |
|||
} |
|||
|
|||
const setWorkClass = (value) => { |
|||
let classValue = 'no-work-class' |
|||
switch (value) { |
|||
case 1: |
|||
classValue = 'zao-work-class' |
|||
break |
|||
case 2: |
|||
classValue = 'wan-work-class' |
|||
break |
|||
case 3: |
|||
classValue = 'ye-work-class' |
|||
break |
|||
default: |
|||
break |
|||
} |
|||
return classValue |
|||
} |
|||
|
|||
const setIconClass = (value) => { |
|||
let classValue = 'ep:sunrise' |
|||
switch (value) { |
|||
case '早': |
|||
classValue = 'ep:sunrise' |
|||
break |
|||
case '中': |
|||
classValue = 'ep:sunny' |
|||
break |
|||
case '晚': |
|||
classValue = 'ep:moon' |
|||
break |
|||
default: |
|||
break |
|||
} |
|||
return classValue |
|||
} |
|||
// 编辑单日排班 |
|||
const handleWorkInfo = (info, data) => { |
|||
hanleDay.value = data |
|||
console.log('info', info) |
|||
drawer.value = true |
|||
if (info && info.length > 0) { |
|||
workInfoList.value = info |
|||
} else { |
|||
workInfoList.value = [] |
|||
} |
|||
} |
|||
const handleClose = () => { |
|||
innerDrawer.value = false |
|||
} |
|||
// 添加单日排班 |
|||
const addWork = () => { |
|||
let info = { |
|||
id: hanleDay.value.day + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: addForm.value.shiftName, |
|||
groupName: addForm.value.groupName, |
|||
startTime: hanleDay.value.day + ' 08:30', |
|||
endTime: hanleDay.value.day + ' 20:30', |
|||
isNotHoliday: 0, |
|||
classId: 1, |
|||
date: hanleDay.value.day, |
|||
sort: addForm.value.sort |
|||
} |
|||
workInfoList.value.push(info) |
|||
if (!viewDate.value[hanleDay.value.day.replace(/-/g, '')]) { |
|||
viewDate.value[hanleDay.value.day.replace(/-/g, '')] = [info] |
|||
} else { |
|||
viewDate.value[hanleDay.value.day.replace(/-/g, '')].push(info) |
|||
} |
|||
|
|||
//row.set(viewDate.value, hanleDay.value, workInfoList.value); |
|||
innerDrawer.value = false |
|||
} |
|||
// 清除单日排班数据 |
|||
const deleteRow = (row, tableData) => { |
|||
let index = row.$index |
|||
tableData.splice(index, 1) |
|||
if (tableData.length > 0) { |
|||
//tableData.$set(viewDate.value, hanleDay.value, tableData.value); |
|||
} else { |
|||
//tableData.$delete(viewDate.value, hanleDay.value); |
|||
} |
|||
} |
|||
const addDomain = () => { |
|||
batchAddForm.value.classData.push({ |
|||
shiftName: '早', |
|||
groupName: '甲', |
|||
key: Date.now() |
|||
}) |
|||
} |
|||
const removeDomain = (item) => { |
|||
if (batchAddForm.value.classData.length > 1) { |
|||
var index = batchAddForm.value.classData.indexOf(item) |
|||
if (index !== -1) { |
|||
batchAddForm.value.classData.splice(index, 1) |
|||
} |
|||
} else { |
|||
message.alert('请至少安排一个排班') |
|||
} |
|||
} |
|||
// 批量添加排班数据 |
|||
const batchAddWork = () => { |
|||
let dateList = batchAddForm.value.batchDate |
|||
let classList = batchAddForm.value.classData |
|||
//console.log('dateList', dateList) |
|||
//console.log('classList', classList) |
|||
let list = [] |
|||
if (dateList && dateList.length > 0) { |
|||
list = enumerateDaysBetweenDates(dateList[0], dateList[1]) |
|||
} |
|||
list.forEach((item) => { |
|||
let workList = [] |
|||
classList.forEach((work) => { |
|||
let info = { |
|||
id: item + Math.random() * 1000, |
|||
ruleName: '三班两运转', |
|||
shiftName: work.shiftName, |
|||
groupName: work.groupName, |
|||
startTime: item + ' 08:30', |
|||
endTime: item + ' 20:30', |
|||
isNotHoliday: 0, |
|||
classId: 1, |
|||
date: item, |
|||
sort: setSortValue(work.shiftName) |
|||
} |
|||
workList.push(info) |
|||
}) |
|||
//set(viewDate.value, item, workList.value); |
|||
viewDate.value[item.replace(/-/g, '')] = workList |
|||
}) |
|||
batchAddDrawer.value = false |
|||
batchAddForm.value = { |
|||
batchDate: [], |
|||
classData: [ |
|||
{ |
|||
shiftName: '早', |
|||
groupName: '甲' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
const handleBatchClose = () => { |
|||
batchAddDrawer.value = false |
|||
} |
|||
//初始化已选中的日期 |
|||
const initHolidayDate = (data) => { |
|||
console.log('🚀 ~ file: App.vue:510 ~ initHolidayDate ~ data:', currentDate.value) |
|||
for (let i in currentDate.value) { |
|||
if (data.day === currentDate.value[i].day) { |
|||
data.isSelected = true |
|||
return '✔' |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 设置禁用值 |
|||
const setDisabled = (date) => { |
|||
// console.log("🚀 ~ file: App.vue:537 ~ setDisabled ~ date:", date) |
|||
if (dayjs(date).isBefore(dateRange.value[0]) || dayjs(date).isAfter(dateRange.value[1])) { |
|||
return 'disabled-date-class' |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
#app-container { |
|||
width: 100%; |
|||
height: 100%; |
|||
margin: 0; |
|||
padding: 0; |
|||
} |
|||
|
|||
.el-table__fixed-right { |
|||
height: 100% !important; |
|||
} |
|||
|
|||
.calender-class { |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
|
|||
.is-selected { |
|||
color: #1989fa; |
|||
} |
|||
|
|||
.el-calendar__body { |
|||
height: 85vh; |
|||
} |
|||
|
|||
.el-calendar-table { |
|||
height: 100%; |
|||
} |
|||
|
|||
.el-calendar-day { |
|||
height: 100% !important; |
|||
} |
|||
|
|||
.day-content-class { |
|||
height: 100px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
.header-class { |
|||
flex: 1; |
|||
display: flex; |
|||
height: 28px; |
|||
flex-direction: row; |
|||
justify-content: space-between; |
|||
} |
|||
|
|||
.day-class { |
|||
flex: 4; |
|||
} |
|||
|
|||
.handle-class { |
|||
flex: 1; |
|||
} |
|||
|
|||
.paiban-class { |
|||
flex: 4; |
|||
display: flex; |
|||
flex-direction: row; |
|||
justify-content: center; |
|||
align-items: flex-end; |
|||
} |
|||
|
|||
.paiban-icon-class { |
|||
font-size: 22px; |
|||
margin: 8px 0 10px 0; |
|||
} |
|||
|
|||
.paiban-name-class { |
|||
padding-top: 10px; |
|||
} |
|||
|
|||
.each-paiban-class { |
|||
text-align: center; |
|||
max-width: 50px; |
|||
margin: 5px 5px 0 5px; |
|||
border-radius: 5px; |
|||
padding: 0 0 5px 0; |
|||
flex: 1; |
|||
} |
|||
|
|||
.zao-work-class { |
|||
background-color: #d9ffd9; |
|||
color: #11be11; |
|||
} |
|||
|
|||
.wan-work-class { |
|||
background-color: #fff0bd; |
|||
color: #fccb2c; |
|||
} |
|||
|
|||
.ye-work-class { |
|||
background-color: #ddeffb; |
|||
color: #2dabff; |
|||
} |
|||
|
|||
.no-work-class { |
|||
text-align: center; |
|||
color: #cacaca; |
|||
} |
|||
|
|||
.icon-class { |
|||
font-size: 20px; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
/* 侧边弹窗 */ |
|||
.add-btn-class { |
|||
margin: 10px; |
|||
float: right; |
|||
} |
|||
|
|||
.change-date-drawer-class .el-calendar__body { |
|||
height: 45%; |
|||
} |
|||
|
|||
.change-date-drawer-class .day-content-class { |
|||
height: 30px; |
|||
} |
|||
|
|||
.disabled-date-class { |
|||
color: #ccc; |
|||
pointer-events: none; |
|||
} |
|||
</style> |
Loading…
Reference in new issue