zhousq
7 months ago
7 changed files with 1349 additions and 641 deletions
@ -0,0 +1,53 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
export interface HolidayVO { |
|||
id: number |
|||
status: string |
|||
remark: string |
|||
holidayYear: string |
|||
holidayType: string |
|||
keyDate: string |
|||
holidayName: string |
|||
holidayDate: Date |
|||
} |
|||
|
|||
// 查询节假日设置列表
|
|||
export const getHolidayPage = async (params) => { |
|||
if (params.isSearch) { |
|||
delete params.isSearch |
|||
const data = {...params} |
|||
return await request.post({ url: '/mes/holiday/senior', data }) |
|||
} else { |
|||
return await request.get({ url: `/mes/holiday/page`, params }) |
|||
} |
|||
} |
|||
|
|||
// 查询节假日设置详情
|
|||
export const getHoliday = async (id: number) => { |
|||
return await request.get({ url: `/mes/holiday/get?id=` + id }) |
|||
} |
|||
|
|||
// 新增节假日设置
|
|||
export const createHoliday = async (data: HolidayVO) => { |
|||
return await request.post({ url: `/mes/holiday/create`, data }) |
|||
} |
|||
|
|||
// 修改节假日设置
|
|||
export const updateHoliday = async (data: HolidayVO) => { |
|||
return await request.put({ url: `/mes/holiday/update`, data }) |
|||
} |
|||
|
|||
// 删除节假日设置
|
|||
export const deleteHoliday = async (id: number) => { |
|||
return await request.delete({ url: `/mes/holiday/delete?id=` + id }) |
|||
} |
|||
|
|||
// 导出节假日设置 Excel
|
|||
export const exportHoliday = async (params) => { |
|||
return await request.download({ url: `/mes/holiday/export-excel`, params }) |
|||
} |
|||
|
|||
// 下载用户导入模板
|
|||
export const importTemplate = () => { |
|||
return request.download({ url: '/mes/holiday/get-import-template' }) |
|||
} |
@ -0,0 +1,81 @@ |
|||
import request from '@/config/axios' |
|||
|
|||
|
|||
|
|||
// 查询节假日
|
|||
export const getDismantlingDetailPage = async (params) => { |
|||
if (params.isSearch) { |
|||
delete params.isSearch |
|||
const data = {...params} |
|||
return await request.post({ url: '/mes/workCalendar/senior', data }) |
|||
} else { |
|||
return await request.get({ url: `/mes/workCalendar/page`, params }) |
|||
} |
|||
} |
|||
|
|||
//班组排班 信息
|
|||
export interface SchedulingcalendarCreateReqVO{ |
|||
keyDate:String, |
|||
//班组编码
|
|||
teamCode:String, |
|||
//班组名称
|
|||
teamName:String, |
|||
//班组类别"
|
|||
teamType:String, |
|||
//班次名称"
|
|||
shiftName:String, |
|||
//班次编码
|
|||
shiftCode:String, |
|||
//上班时间
|
|||
startTime:String, |
|||
//下班时间"
|
|||
endTime:String, |
|||
//工作日期
|
|||
workDate:String, |
|||
//倒班规则
|
|||
shiftRule:String, |
|||
//倒班类型
|
|||
shiftRate:String, |
|||
sort:number |
|||
} |
|||
//
|
|||
// 查询班组列表
|
|||
export const getTeamList = async (params) => { |
|||
return await request.get({ url: `/wms/team/page`, params }) |
|||
} |
|||
|
|||
// 保存排班信息
|
|||
export const saveWorkPlan = async (data:SchedulingcalendarCreateReqVO ) => { |
|||
return await request.post({ url: `/mes/schedulingcalendar/create`, data }) |
|||
} |
|||
// 删除班组排班信息
|
|||
export const deleteWorkPlan = async (data) => { |
|||
return await request.post({ url: `/mes/schedulingcalendar/deleteTeam`, data}) |
|||
} |
|||
//批量保存排班信息
|
|||
export const createBatch = async (data:any) => { |
|||
return await request.post({ url: `/mes/schedulingcalendar/createBatch`, data }) |
|||
} |
|||
//批量对象方式保存排班信息--保留
|
|||
export const createObj= async (data:any) => { |
|||
return await request.post({ url: `/mes/schedulingcalendar/createObj`, data }) |
|||
} |
|||
|
|||
// 查询排班信息 code startTime:开始时间" endTime:结束时间")
|
|||
export const getWorkPlan = async (params ) => { |
|||
return await request.get({ url: `/mes/schedulingcalendar/getList`,params }) |
|||
} |
|||
// 查询班次信息
|
|||
export const getShiftInfos = async (code:any) => { |
|||
return await request.get({ url: `/mes/schedulingcalendar/shift?code=`+code}) |
|||
} |
|||
//查询节假日信息
|
|||
export const getHolidays = async (year:any) => { |
|||
return await request.get({ url: `/mes/holiday/listByYear?year=`+year}) |
|||
} |
|||
|
|||
// 导出排班信息
|
|||
export const exportWorkPlan = async (params) => { |
|||
return await request.download({ url: `/mes/schedulingcalendar/export-excel`, params }) |
|||
} |
|||
|
@ -1,641 +0,0 @@ |
|||
<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> |
@ -0,0 +1,109 @@ |
|||
import type { CrudSchema } from '@/hooks/web/useCrudSchemas' |
|||
import { dateFormatter } from '@/utils/formatTime' |
|||
|
|||
// 表单校验
|
|||
export const HolidayRules = reactive({ |
|||
}) |
|||
|
|||
export const Holiday = useCrudSchemas(reactive<CrudSchema[]>([ |
|||
{ |
|||
label: '主键', |
|||
field: 'id', |
|||
sort: 'custom', |
|||
isForm: false, |
|||
}, |
|||
|
|||
|
|||
{ |
|||
label: 'KEY', |
|||
field: 'keyDate', |
|||
sort: 'custom', |
|||
isSearch: false, |
|||
isTable:false, |
|||
isForm:false |
|||
}, |
|||
{ |
|||
label: '节日名称', |
|||
field: 'holidayName', |
|||
sort: 'custom', |
|||
isSearch: true, |
|||
}, |
|||
{ |
|||
label: '节日类型;', |
|||
field: 'holidayType', |
|||
sort: 'custom', |
|||
isSearch: true, |
|||
dictType: DICT_TYPE.HOLIDAY_TYPE, |
|||
dictClass: 'string', |
|||
form: { |
|||
component: 'Select', |
|||
value: '1', |
|||
}, |
|||
}, |
|||
{ |
|||
label: '节日年份', |
|||
field: 'holidayYear', |
|||
sort: 'custom', |
|||
isSearch: true, |
|||
isForm:false, |
|||
isTable:true, |
|||
form: { |
|||
component: 'InputNumber', |
|||
value: '2023', |
|||
}, |
|||
}, |
|||
{ |
|||
label: '节日日期', |
|||
field: 'holidayDate', |
|||
sort: 'custom', |
|||
formatter: dateFormatter, |
|||
isSearch: true, |
|||
search: { |
|||
component: 'DatePicker', |
|||
componentProps: { |
|||
type: 'date', |
|||
valueFormat: 'YYYY-MM-DD', |
|||
} |
|||
}, |
|||
form: { |
|||
component: 'DatePicker', |
|||
componentProps: { |
|||
type: 'date', |
|||
valueFormat: 'x' |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
label: '状态', |
|||
field: 'status', |
|||
sort: 'custom', |
|||
dictType: DICT_TYPE.QUALIFY_STATUS, |
|||
dictClass: 'string', |
|||
isForm: true, |
|||
isSearch: false, |
|||
isTable: true, |
|||
form: { |
|||
component: 'Switch', |
|||
value: '1', |
|||
componentProps: { |
|||
inactiveValue: '2', |
|||
activeValue: '1' |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
label: '备注', |
|||
field: 'remark', |
|||
sort: 'custom', |
|||
isSearch: false, |
|||
}, |
|||
{ |
|||
label: '操作', |
|||
field: 'action', |
|||
isForm: false, |
|||
table: { |
|||
width: 150, |
|||
fixed: 'right' |
|||
} |
|||
} |
|||
])) |
@ -0,0 +1,226 @@ |
|||
<template> |
|||
<ContentWrap> |
|||
<!-- 搜索工作栏 --> |
|||
<Search :schema="Holiday.allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" /> |
|||
</ContentWrap> |
|||
|
|||
<!-- 列表头部 --> |
|||
<TableHead |
|||
:HeadButttondata="HeadButttondata" |
|||
@button-base-click="buttonBaseClick" |
|||
:routeName="routeName" |
|||
@updataTableColumns="updataTableColumns" |
|||
@searchFormClick="searchFormClick" |
|||
:allSchemas="Holiday.allSchemas" |
|||
/> |
|||
|
|||
<!-- 列表 --> |
|||
<ContentWrap> |
|||
<Table |
|||
:columns="tableColumns" |
|||
:data="tableObject.tableList" |
|||
:loading="tableObject.loading" |
|||
:pagination="{ |
|||
total: tableObject.total |
|||
}" |
|||
v-model:pageSize="tableObject.pageSize" |
|||
v-model:currentPage="tableObject.currentPage" |
|||
v-model:sort="tableObject.sort" |
|||
> |
|||
<template #holidayName="{row}"> |
|||
<el-button type="primary" link @click="openDetail(row, row.holidayName, row.holidayName)"> |
|||
<span>{{ row.holidayName }}</span> |
|||
</el-button> |
|||
</template> |
|||
<template #action="{ row }"> |
|||
<ButtonBase :Butttondata="butttondata" @button-base-click="buttonTableClick($event,row)" /> |
|||
</template> |
|||
</Table> |
|||
</ContentWrap> |
|||
|
|||
<!-- 表单弹窗:添加/修改 --> |
|||
<BasicForm |
|||
ref="basicFormRef" |
|||
@success="formsSuccess" |
|||
:rules="HolidayRules" |
|||
:formAllSchemas="Holiday.allSchemas" |
|||
:apiUpdate="HolidayApi.updateHoliday" |
|||
:apiCreate="HolidayApi.createHoliday" |
|||
@searchTableSuccess="searchTableSuccess" |
|||
:isBusiness="false" |
|||
/> |
|||
|
|||
<!-- 详情 --> |
|||
<Detail ref="detailRef" :isBasic="false" :is-basic-mes="true" :allSchemas="Holiday.allSchemas" :api-page="HolidayApi.getHolidayPage" :detailAllSchemas="Holiday.allSchemas"/> |
|||
|
|||
<!-- 导入 --> |
|||
<ImportForm ref="importFormRef" url="/mes/holiday/import" :importTemplateData="importTemplateData" @success="importSuccess" /> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import download from '@/utils/download' |
|||
import { Holiday,HolidayRules } from './holiday.data' |
|||
import * as HolidayApi from '@/api/mes/holiday' |
|||
import * as defaultButtons from '@/utils/disposition/defaultButtons' |
|||
import TableHead from '@/components/TableHead/src/TableHead.vue' |
|||
import ImportForm from '@/components/ImportForm/src/ImportForm.vue' |
|||
import Detail from '../../mes/components/Detail.vue' |
|||
|
|||
defineOptions({ name: 'Holiday' }) |
|||
|
|||
const message = useMessage() // 消息弹窗 |
|||
const { t } = useI18n() // 国际化 |
|||
|
|||
const route = useRoute() // 路由信息 |
|||
const routeName = ref() |
|||
routeName.value = route.name |
|||
const tableColumns = ref(Holiday.allSchemas.tableColumns) |
|||
|
|||
// 查询页面返回 |
|||
const searchTableSuccess = (formField, searchField, val, formRef) => { |
|||
nextTick(() => { |
|||
const setV = {} |
|||
setV[formField] = val[0][searchField] |
|||
formRef.setValues(setV) |
|||
}) |
|||
} |
|||
|
|||
// 字段设置 更新主列表字段 |
|||
const updataTableColumns = (val) => { |
|||
tableColumns.value = val |
|||
} |
|||
|
|||
const { tableObject, tableMethods } = useTable({ |
|||
getListApi: HolidayApi.getHolidayPage // 分页接口 |
|||
}) |
|||
|
|||
// 获得表格的各种操作 |
|||
const { getList, setSearchParams } = tableMethods |
|||
|
|||
// 列表头部按钮 |
|||
const HeadButttondata = [ |
|||
defaultButtons.defaultAddBtn({hasPermi:'mes:holiday:create'}), // 新增 |
|||
defaultButtons.defaultImportBtn({hasPermi:'mes:holiday:import'}), // 导入 |
|||
defaultButtons.defaultExportBtn({hasPermi:'mes:holiday:export'}), // 导出 |
|||
defaultButtons.defaultFreshBtn(null), // 刷新 |
|||
defaultButtons.defaultFilterBtn(null), // 筛选 |
|||
defaultButtons.defaultSetBtn(null), // 设置 |
|||
|
|||
] |
|||
|
|||
// 头部按钮事件 |
|||
const buttonBaseClick = (val, item) => { |
|||
if (val == 'add') { // 新增 |
|||
openForm('create') |
|||
} else if (val == 'import') { // 导入 |
|||
handleImport() |
|||
} else if (val == 'export') { // 导出 |
|||
handleExport() |
|||
} else if (val == 'refresh') { // 刷新 |
|||
getList() |
|||
} else if (val == 'filtrate') { // 筛选 |
|||
} else { // 其他按钮 |
|||
console.log('其他按钮', item) |
|||
} |
|||
} |
|||
|
|||
// 列表-操作按钮 |
|||
const butttondata = [ |
|||
defaultButtons.mainListEditBtn({hasPermi:'mes:holiday:update'}), // 编辑 |
|||
defaultButtons.mainListDeleteBtn({hasPermi:'mes:holiday:delete'}), // 删除 |
|||
] |
|||
|
|||
// 列表-操作按钮事件 |
|||
const buttonTableClick = async (val, row) => { |
|||
if (val == 'edit') { // 编辑 |
|||
openForm('update', row) |
|||
} else if (val == 'delete') { // 删除 |
|||
handleDelete(row.id) |
|||
} |
|||
} |
|||
|
|||
/** 添加/修改操作 */ |
|||
const basicFormRef = ref() |
|||
const openForm = (type: string, row?: any) => { |
|||
basicFormRef.value.open(type, row) |
|||
} |
|||
|
|||
// form表单提交 |
|||
const formsSuccess = async (formType,data) => { |
|||
if (formType === 'create') { |
|||
await HolidayApi.createHoliday(data) |
|||
message.success(t('common.createSuccess')) |
|||
} else { |
|||
await HolidayApi.updateHoliday(data) |
|||
message.success(t('common.updateSuccess')) |
|||
} |
|||
basicFormRef.value.dialogVisible = false |
|||
getList() |
|||
} |
|||
|
|||
/** 详情操作 */ |
|||
const detailRef = ref() |
|||
const openDetail = (row: any, titleName: any, titleValue: any) => { |
|||
detailRef.value.openDetail(row, titleName, titleValue, 'basicHoliday') |
|||
} |
|||
|
|||
/** 删除按钮操作 */ |
|||
const handleDelete = async (id: number) => { |
|||
try { |
|||
// 删除的二次确认 |
|||
await message.delConfirm() |
|||
// 发起删除 |
|||
await HolidayApi.deleteHoliday(id) |
|||
message.success(t('common.delSuccess')) |
|||
// 刷新列表 |
|||
await getList() |
|||
} catch {} |
|||
} |
|||
|
|||
/** 导出按钮操作 */ |
|||
const exportLoading = ref(false) // 导出的加载中 |
|||
const handleExport = async () => { |
|||
try { |
|||
// 导出的二次确认 |
|||
await message.exportConfirm() |
|||
// 发起导出 |
|||
exportLoading.value = true |
|||
const data = await HolidayApi.exportHoliday(tableObject.params) |
|||
download.excel(data, '节假日设置.xlsx') |
|||
} catch { |
|||
} finally { |
|||
exportLoading.value = false |
|||
} |
|||
} |
|||
|
|||
/** 导入 */ |
|||
const importFormRef = ref() |
|||
const handleImport = () => { |
|||
importFormRef.value.open() |
|||
} |
|||
// 导入附件弹窗所需的参数 |
|||
const importTemplateData = reactive({ |
|||
templateUrl: '', |
|||
templateTitle: '节假日设置导入模版.xlsx' |
|||
}) |
|||
// 导入成功之后 |
|||
const importSuccess = () => { |
|||
getList() |
|||
} |
|||
|
|||
// 筛选提交 |
|||
const searchFormClick = (searchData) => { |
|||
tableObject.params = { |
|||
isSearch: true, |
|||
filters: searchData.filters |
|||
} |
|||
getList() // 刷新当前列表 |
|||
} |
|||
|
|||
/** 初始化 **/ |
|||
onMounted(async () => { |
|||
getList() |
|||
importTemplateData.templateUrl = await HolidayApi.importTemplate() |
|||
}) |
|||
|
|||
</script> |
@ -0,0 +1,879 @@ |
|||
<template> |
|||
<div class="app-container"> |
|||
<el-container> |
|||
<el-aside width="300px"> |
|||
<el-row> |
|||
<el-col :span="24"> |
|||
<el-select |
|||
v-model="groupType" |
|||
placeholder="选择班组类别" |
|||
style="height: 40px" |
|||
@change="handleGroupTypeChange" |
|||
> |
|||
<el-option |
|||
v-for="dict in getStrDictOptions(DICT_TYPE.BASIC_TEAM_TYPE)" |
|||
:key="dict.value" |
|||
:label="dict.label" |
|||
:value="dict.value" |
|||
> |
|||
<span style="float: left">{{ dict.label }}</span> |
|||
<span style="float: right; color: var(--el-text-color-secondary); font-size: 13px"> |
|||
{{ dict.value }} |
|||
</span> |
|||
</el-option> |
|||
</el-select> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row> |
|||
<el-col :span="24"> |
|||
<template #default> |
|||
<el-table |
|||
:data="tableData" |
|||
ref="refTableTeams" |
|||
highlight-current-row |
|||
@current-change="handleTableCurrentChange" |
|||
@row-dblclick="handleClick('')" |
|||
> |
|||
<el-table-column type="index" width="50" /> |
|||
<el-table-column prop="code" label="班组编码" /> |
|||
<el-table-column prop="name" label="班组名称" /> |
|||
<el-table-column label="删除排班" > |
|||
<template #default="scope"> |
|||
<el-button type="text" size="mini" @click="handleDelete(scope.row)">删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
|
|||
<el-pagination |
|||
small |
|||
:page-size="queryPage.pageSize" |
|||
background |
|||
layout="prev, pager, next" |
|||
:total="queryPage.pageTotal" |
|||
class="mt-4" |
|||
@current-change="handleGroupPageChange" |
|||
/> |
|||
</template> |
|||
</el-col> |
|||
</el-row> |
|||
</el-aside> |
|||
<el-main> |
|||
<div class="calender-class"> |
|||
<el-calendar ref="calendarMain"> |
|||
<template #header="{ date }"> |
|||
<span>排班日历</span> |
|||
<span>{{ date }}</span> |
|||
<el-button-group> |
|||
<el-button size="small" @click="selectDate('prev-month')"> 上一月 </el-button> |
|||
<el-button size="small" @click="selectDate('today')">今天</el-button> |
|||
<el-button size="small" @click="selectDate('next-month')"> 下一月 </el-button> |
|||
<el-button size="small" type="primary" @click="handleClick('batch')" |
|||
>批量排班</el-button |
|||
> |
|||
</el-button-group> |
|||
</template> |
|||
<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 |
|||
v-if="holiday[data.day.replace(/-/g, '')]" |
|||
size="mini" |
|||
circle |
|||
style="background-color: chocolate" |
|||
><Icon icon="ep:star" />{{holiday[data.day.replace(/-/g, '')].holidayName}} |
|||
</el-button> |
|||
</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(setSortValue(dayValue.shiftName)) |
|||
]" |
|||
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.teamName }}</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 |
|||
v-if="holiday[data.day.replace(/-/g, '')]" |
|||
size="mini" |
|||
circle |
|||
style="background-color: chocolate" |
|||
><Icon icon="ep:star" />{{holiday[data.day.replace(/-/g, '')].holidayName}} |
|||
</el-button> |
|||
</div> |
|||
<div class="handle-class"> |
|||
<el-button size="mini" circle @click="handleWorkInfo(null, 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> |
|||
</el-main> |
|||
</el-container> |
|||
<!-- 批量排班抽屉弹窗 --> |
|||
<div> |
|||
<el-drawer :title="batchTitle" v-model="batchAddDrawer" size="40%"> |
|||
<div class="demo-drawer_content"> |
|||
<el-form v-model="batchAddForm"> |
|||
<el-form-item label="排班日期:" label-width="120px"> |
|||
<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-form-item label="规则类型:" label-width="120px"> |
|||
<!-- <el-button type="primary" @click="addDomain" link> <Icon icon="ep:plus" /> </el-button> --> |
|||
<el-radio-group v-model="ruleType" @change="handleRuleType"> |
|||
<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="120px"> |
|||
<el-switch v-model="batchAddForm.excludeRestDay" /> |
|||
</el-form-item> |
|||
|
|||
<el-table :data="shiftTableData" ref="shiftTable" style="width: 100%"> |
|||
<el-table-column label="班次" prop="shiftName" /> |
|||
<el-table-column label="上班时间" prop="startTime"> |
|||
<template #default="scope"> |
|||
<el-time-picker |
|||
format="HH:mm" |
|||
value-format="HH:mm" |
|||
v-model="scope.row.startTime" |
|||
/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="下班时间" prop="endTime"> |
|||
<template #default="scope"> |
|||
<el-time-picker |
|||
format="HH:mm" |
|||
value-format="HH:mm" |
|||
v-model="scope.row.endTime" |
|||
/> </template |
|||
></el-table-column> |
|||
</el-table> |
|||
</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"> |
|||
<div class="demo-drawer__content"> |
|||
<el-form v-model="addForm"> |
|||
<el-form-item label="规则类型:" label-width="120px"> |
|||
<!-- <el-button type="primary" @click="addDomain" link> <Icon icon="ep:plus" /> </el-button> --> |
|||
<el-radio-group v-model="ruleType" @change="handleRuleType"> |
|||
<el-radio label="一班倒">一班倒</el-radio> |
|||
<el-radio label="两班倒">两班倒</el-radio> |
|||
<el-radio label="三班倒">三班倒</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-table :data="shiftTableData" ref="shiftTable" style="width: 100%"> |
|||
<el-table-column label="班次" prop="shiftName" /> |
|||
<el-table-column label="上班时间" prop="startTime"> |
|||
<template #default="scope"> |
|||
<el-time-picker |
|||
format="HH:mm" |
|||
value-format="HH:mm" |
|||
v-model="scope.row.startTime" |
|||
/> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="下班时间" prop="endTime"> |
|||
<template #default="scope"> |
|||
<el-time-picker |
|||
format="HH:mm" |
|||
value-format="HH:mm" |
|||
v-model="scope.row.endTime" |
|||
/> </template |
|||
></el-table-column> |
|||
</el-table> |
|||
</el-form> |
|||
<div class="demo-drawer__footer"> |
|||
<el-button @click="handleBatchClose">取 消</el-button> |
|||
<el-button type="primary" @click="addWork"> 保存 </el-button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</el-drawer> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import { useMessage } from '@/hooks/web/useMessage' |
|||
import dayjs from 'dayjs' |
|||
import { ref, watch, nextTick } from 'vue' |
|||
import type { CalendarDateType, CalendarInstance } from 'element-plus' |
|||
import { DICT_TYPE, getStrDictOptions } from '@/utils/dict' |
|||
import * as workCalendarApi from '@/api/mes/workcalendar' |
|||
|
|||
const message = useMessage() // 消息弹窗 |
|||
const ruleType = ref('一班倒') //排班规则 |
|||
const currentDate = ref(dayjs().format('YYYY-MM-DD')) |
|||
const batchTitle = ref('批量排班') |
|||
|
|||
const queryPage = ref({ pageNo: 1, pageSize: 20, pageTotal: 20, teamGroup: '' }) |
|||
const tableData = ref([]) //班组列表 |
|||
const groupType = ref([]) //班组类型 |
|||
const shiftTableData = ref([{ shiftName: '早', startTime: '08:00', endTime: '16:00' }]) |
|||
|
|||
//节假日数据 |
|||
const holiday = ref({ |
|||
'20240501': { |
|||
holidayName: '休', |
|||
holidayType: '法定', |
|||
date: '2024-05-01' |
|||
}, |
|||
'20240502': { |
|||
holidayName: '休', |
|||
holidayType: '法定', |
|||
date: '2024-05-02' |
|||
}, |
|||
'20240503': { |
|||
holidayName: '休', |
|||
holidayType: '法定', |
|||
date: '2024-05-03' |
|||
}, |
|||
'20240504': { |
|||
holidayName: '休', |
|||
holidayType: '法定', |
|||
date: '2024-05-04' |
|||
}, |
|||
'20240505': { |
|||
holidayName: '休', |
|||
holidayType: '法定', |
|||
date: '2024-05-05' |
|||
} |
|||
}) |
|||
//排班数据 |
|||
const viewDate = ref({}) |
|||
//今日数据 |
|||
const thisDay = ref() |
|||
//今日班次数据 |
|||
const thisDayWork = ref() |
|||
const ending = ref() |
|||
const dragging = ref() |
|||
const batchAddDrawer = ref(false) |
|||
// 批量添加 |
|||
const batchAddForm = ref({ |
|||
batchDate: [], |
|||
excludeRestDay:true |
|||
}) |
|||
// 单日添加 |
|||
const addForm = ref({ |
|||
shiftName: '早', |
|||
teamName: 'chongya01', |
|||
ruleCode: '1', |
|||
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' |
|||
}) |
|||
//班组选择 |
|||
interface Team { |
|||
code: string |
|||
name: string |
|||
class: string |
|||
} |
|||
|
|||
const currentRow = ref() //当前行的值 |
|||
const handleTableCurrentChange = (val: Team) => { |
|||
currentRow.value = val |
|||
} |
|||
|
|||
const calendarMain = ref<CalendarInstance>() |
|||
//console.log("🚀 ~ file: App.vue:617 ~ getViewData ~ calendarMain:",calendarMain) |
|||
///处理排班和tablerow切换 |
|||
const handleClick = (type) => { |
|||
if (currentRow.value) { |
|||
if (type == 'single') { |
|||
drawer.value = true |
|||
} else if (type == 'batch') { |
|||
batchTitle.value = '批量排班[' + currentRow.value.name + ']' |
|||
batchAddDrawer.value = true |
|||
} |
|||
//console.log("🚀 ~ file: App.vue:617 ~ getViewData ~ currentDate.value:",currentDate.value) |
|||
getViewData(currentRow.value.code, currentDate.value.slice(0, 8) + '01', dayjs(currentDate.value).endOf('month').format('YYYY-MM-DD')) |
|||
} else { |
|||
message.error('请选择一个班组!') |
|||
return |
|||
} |
|||
} |
|||
|
|||
const handleRuleType = (value: string) => { |
|||
if (value == '三班倒') { |
|||
shiftTableData.value = [ |
|||
{ |
|||
shiftName: '早', |
|||
startTime: shiftTime.value['早'].startTime, |
|||
endTime: shiftTime.value['早'].endTime |
|||
}, |
|||
{ |
|||
shiftName: '中', |
|||
startTime: shiftTime.value['中'].startTime, |
|||
endTime: shiftTime.value['中'].endTime |
|||
}, |
|||
{ |
|||
shiftName: '晚', |
|||
startTime: shiftTime.value['晚'].startTime, |
|||
endTime: shiftTime.value['晚'].endTime |
|||
} |
|||
] |
|||
} else if (value == '两班倒') { |
|||
shiftTableData.value = [ |
|||
{ |
|||
shiftName: '早', |
|||
startTime: shiftTime.value['早'].startTime, |
|||
endTime: shiftTime.value['早'].endTime |
|||
}, |
|||
{ |
|||
shiftName: '中', |
|||
startTime: shiftTime.value['中'].startTime, |
|||
endTime: shiftTime.value['中'].endTime |
|||
} |
|||
] |
|||
} else { |
|||
shiftTableData.value = [ |
|||
{ |
|||
shiftName: '早', |
|||
startTime: shiftTime.value['早'].startTime, |
|||
endTime: shiftTime.value['早'].endTime |
|||
} |
|||
] |
|||
} |
|||
} |
|||
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 |
|||
} |
|||
} |
|||
) |
|||
onMounted( |
|||
async function () { |
|||
let res=await workCalendarApi.getHolidays(dayjs(currentDate.value).year()) |
|||
holiday.value=res |
|||
//console.log('🚀 ~ file: App.vue:571 ~ onMounted ~ getHolidays:', res) |
|||
} |
|||
) |
|||
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])) |
|||
nextTick(() => { |
|||
dragging.value = null |
|||
ending.value = null |
|||
}) |
|||
} |
|||
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) |
|||
|
|||
while (SDate.isBefore(EDate)) { |
|||
daysList.push(SDate.format('YYYY-MM-DD')) |
|||
SDate = SDate.add(1, 'day') |
|||
} |
|||
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) => { |
|||
if (currentRow.value) { |
|||
hanleDay.value = data |
|||
drawer.value = true |
|||
if (info != undefined && info.length > 0) { |
|||
workInfoList.value = info |
|||
} else { |
|||
workInfoList.value = [] |
|||
} |
|||
} else { |
|||
message.error('请选择一个班组!') |
|||
return |
|||
} |
|||
} |
|||
const handleClose = () => { |
|||
innerDrawer.value = false |
|||
} |
|||
// //班次时间 |
|||
const shiftTime = ref({ |
|||
早: { startTime: '8:00', endTime: '16:00' }, |
|||
中: { startTime: '16:00', endTime: '24:00' }, |
|||
晚: { startTime: '00:00', endTime: '8:00' } |
|||
}) |
|||
// 添加单日排班 |
|||
const addWork = () => { |
|||
let saveList = [] |
|||
let shiftData = shiftTableData.value //班次 |
|||
let keyDate = dayjs(hanleDay.value.day).format('YYYYMMDD') |
|||
shiftData.forEach((shift) => { |
|||
let info = { |
|||
keyDate: keyDate, |
|||
//班组编码 |
|||
teamCode: currentRow.value.code, |
|||
//班组名称 |
|||
teamName: currentRow.value.name, |
|||
//班组类别" |
|||
teamType: queryPage.value.teamGroup, |
|||
//班次名称" |
|||
shiftName: shift.shiftName, |
|||
//班次编码 |
|||
shiftCode: shift.shiftName, |
|||
//上班时间 |
|||
startTime: shift.startTime, |
|||
//下班时间" |
|||
endTime: shift.endTime, |
|||
//工作日期 |
|||
//workDate:work, |
|||
workDateString: hanleDay.value.day, |
|||
//倒班规则 |
|||
shiftRule: ruleType.value, |
|||
//倒班类型 |
|||
shiftRate: '月', |
|||
sort: setSortValue(shift.shiftName) |
|||
} |
|||
|
|||
saveList.push(info) |
|||
|
|||
}) |
|||
//console.log('🚀 ~ file: App.vue:571 ~ addWork ~ saveList:', saveList) |
|||
savePlan(saveList) |
|||
getViewData(currentRow.value.code, hanleDay.value.day, hanleDay.value.day) |
|||
|
|||
drawer.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 batchAddWork = () => { |
|||
let dateList = batchAddForm.value.batchDate //时间范围 |
|||
//let classList = batchAddForm.value.classData |
|||
let shiftData = shiftTableData.value //班次 |
|||
//console.log('dateList', dateList) |
|||
//console.log('classList', classList) |
|||
let list = [] |
|||
//生成时间段 |
|||
if (dateList && dateList.length > 0) { |
|||
list = enumerateDaysBetweenDates(dateList[0], dateList[1]) |
|||
} |
|||
//当前每天生成一个排班计划, 排班规则 班次计划 |
|||
let saveList = [] |
|||
let flag=false//过滤项目 |
|||
list.forEach((item) => { |
|||
let keyDate = dayjs(item).format('YYYYMMDD') |
|||
if(batchAddForm.value.excludeRestDay){ |
|||
if(dayjs(item).day()==0||dayjs(item).day()==6){ |
|||
flag=true |
|||
}else{ |
|||
flag=false |
|||
} |
|||
}else{ |
|||
flag=false |
|||
} |
|||
if (!holiday.value[keyDate] && !flag) { |
|||
//let workList=[] |
|||
shiftData.forEach((shift) => { |
|||
let info = { |
|||
keyDate: keyDate, |
|||
//班组编码 |
|||
teamCode: currentRow.value.code, |
|||
//班组名称 |
|||
teamName: currentRow.value.name, |
|||
//班组类别" |
|||
teamType: queryPage.value.teamGroup, |
|||
//班次名称" |
|||
shiftName: shift.shiftName, |
|||
//班次编码 |
|||
shiftCode: shift.shiftName, |
|||
//上班时间 |
|||
startTime: shift.startTime, |
|||
//下班时间" |
|||
endTime: shift.endTime, |
|||
//工作日期SchedulingcalendarCreateReqVO(super=SchedulingcalendarBaseVO(keyDate=20240506, teamCode=T01, teamName=测试添加, teamType=1, shiftName=早, shiftCode=早, startTime=08:00, endTime=16:00, status=null, workDate=null, shiftRule=一班倒, shiftRate=月, workDateStr=null)) |
|||
//workDate:work, |
|||
workDateString: item, |
|||
//倒班规则 |
|||
shiftRule: ruleType.value, |
|||
//倒班类型 |
|||
shiftRate: '月', |
|||
sort: setSortValue(shift.shiftName) |
|||
} |
|||
//workList.push(info) |
|||
saveList.push(info) |
|||
}) |
|||
} |
|||
}) |
|||
|
|||
savePlan(saveList) |
|||
getViewData(currentRow.value.code, dateList[0], dateList[1]) |
|||
batchAddDrawer.value = false |
|||
batchAddForm.value = { |
|||
batchDate: [], |
|||
excludeRestDay:true |
|||
} |
|||
} |
|||
const handleBatchClose = () => { |
|||
batchAddDrawer.value = false |
|||
} |
|||
const savePlan = async (workList) => { |
|||
await workCalendarApi.createBatch(workList) |
|||
//await workCalendarApi.createObj(workList); |
|||
} |
|||
const getViewData = async (teamCode: any, startDate: any, endDate: any) => { |
|||
let params = { |
|||
code: teamCode, |
|||
startTime: startDate, |
|||
endTime: endDate |
|||
} |
|||
let res = await workCalendarApi.getWorkPlan(params) |
|||
//if(res) |
|||
viewDate.value = res |
|||
//workInfoList.value =viewDate.value |
|||
//console.log('🚀 ~ file: App.vue:672 ~ getViewData ~ getViewData:', viewDate.value) |
|||
} |
|||
// 设置禁用值 |
|||
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' |
|||
} |
|||
} |
|||
|
|||
const selectDate = (val: CalendarDateType) => { |
|||
if (!calendarMain.value) return |
|||
if (val === 'prev-month') { |
|||
currentDate.value = dayjs(currentDate.value).subtract(1, 'month').format('YYYY-MM-DD') |
|||
//console.log('🚀 ~ file: App.vue:644 ~ getViewData ~ datedd:', currentDate.value) |
|||
} |
|||
if (val === 'next-month') { |
|||
currentDate.value = dayjs(currentDate.value).add(1, 'month').format('YYYY-MM-DD') |
|||
//console.log('🚀 ~ file: App.vue:644 ~ getViewData ~ datedd:', currentDate.value) |
|||
} |
|||
if (val === 'today') { |
|||
currentDate.value = dayjs(new Date()).format('YYYY-MM-DD') |
|||
//console.log('🚀 ~ file: App.vue:644 ~ getViewData ~ datedd:', currentDate.value) |
|||
} |
|||
calendarMain.value.selectDate(val) |
|||
} |
|||
|
|||
const handleGroupTypeChange = (val: any) => { |
|||
queryPage.value.teamGroup = val |
|||
getTeamList() |
|||
} |
|||
const handleGroupPageChange = (val: number) => { |
|||
;(queryPage.value.pageNo = val), getTeamList() |
|||
} |
|||
const getTeamList = async () => { |
|||
let query = { |
|||
pageNo: queryPage.value.pageNo, |
|||
pageSize: queryPage.value.pageSize, |
|||
teamGroup: queryPage.value.teamGroup |
|||
} |
|||
let res = await workCalendarApi.getTeamList(query) |
|||
queryPage.value.pageTotal = res.total |
|||
tableData.value = res.list |
|||
} |
|||
|
|||
//删除班组排班 |
|||
const handleDelete=(row:any)=>{ |
|||
message.delConfirm('确认要删除['+row.name+']班组当月排班数据吗?', 'Warning').then(() => { |
|||
//console.log('🚀 ~ file: App.vue:720 ~ handleDelete ~ :', dayjs(currentDate.value).endOf('month').format('YYYY-MM-DD')) |
|||
deleteWorkPlan(row.code,currentDate.value.slice(0, 8) + '01', dayjs(currentDate.value).endOf('month').format('YYYY-MM-DD')) |
|||
|
|||
}) |
|||
// .catch(() => { |
|||
|
|||
// }) |
|||
|
|||
} |
|||
const deleteWorkPlan=async (code:any,startTime:any,endTime:any)=>{ |
|||
let data={ |
|||
code:code, |
|||
startTime:startTime, |
|||
endTime: endTime |
|||
} |
|||
console.log('🚀 ~ file: App.vue:720 ~ deleteWorkPlan ~ :', data) |
|||
workCalendarApi.deleteWorkPlan(data) |
|||
getViewData(code, startTime,endTime) |
|||
} |
|||
</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; |
|||
} |
|||
.holiday-class { |
|||
flex: 1; |
|||
flex-direction: column; |
|||
left: 1px; |
|||
} |
|||
.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; |
|||
font-size: small; |
|||
color: #11be11; |
|||
} |
|||
|
|||
.wan-work-class { |
|||
background-color: #fff0bd; |
|||
font-size: small; |
|||
color: #fccb2c; |
|||
} |
|||
|
|||
.ye-work-class { |
|||
background-color: #ddeffb; |
|||
font-size: small; |
|||
color: #2dabff; |
|||
} |
|||
|
|||
.no-work-class { |
|||
text-align: center; |
|||
font-size: small; |
|||
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