refactor(mes): 优化假期设置交互,精简接口对齐后端

1. 右键改左键点击弹出设置弹窗,阻止非当前月切换
2. 弹窗打开时调 get-by-day 接口回显已有 type 和 remark
3. 新增备注(remark)输入框,时间戳传参用 formatDate 转换
4. HolidayType 枚举抽取到 mes/utils/constants.ts 统一管理
5. 精简 API:移除 page/export/update/delete,create 改为 save
pull/871/MERGE
YunaiV 2026-02-16 20:59:01 +08:00
parent f40b415b9c
commit 369d3bbff2
5 changed files with 70 additions and 95 deletions

View File

@ -3,10 +3,8 @@ import request from '@/config/axios'
// MES 假期设置 VO // MES 假期设置 VO
export interface CalHolidayVO { export interface CalHolidayVO {
id: number // 编号 id: number // 编号
theDay: string // 日期 day: number // 日期(时间戳)
type: string // 日期类型 type: number // 日期类型
startTime: string // 开始时间
endTime: string // 结束时间
remark: string // 备注 remark: string // 备注
attribute1: string // 预留字段1 attribute1: string // 预留字段1
attribute2: string // 预留字段2 attribute2: string // 预留字段2
@ -17,12 +15,7 @@ export interface CalHolidayVO {
// MES 假期设置 API // MES 假期设置 API
export const CalHolidayApi = { export const CalHolidayApi = {
// 查询假期设置分页 // 查询所有假期设置列表
getHolidayPage: async (params: any) => {
return await request.get({ url: `/mes/cal/holiday/page`, params })
},
// 查询所有假期设置列表(日历组件用,不分页)
getHolidayList: async () => { getHolidayList: async () => {
return await request.get({ url: `/mes/cal/holiday/list` }) return await request.get({ url: `/mes/cal/holiday/list` })
}, },

View File

@ -255,5 +255,7 @@ export enum DICT_TYPE {
// ========== MES - 制造执行系统模块 ========== // ========== MES - 制造执行系统模块 ==========
MES_CLIENT_TYPE = 'mes_client_type', // MES 客户类型 MES_CLIENT_TYPE = 'mes_client_type', // MES 客户类型
MES_VENDOR_LEVEL = 'mes_vendor_level', // MES 供应商级别 MES_VENDOR_LEVEL = 'mes_vendor_level', // MES 供应商级别
MES_CAL_HOLIDAY_TYPE = 'mes_cal_holiday_type' // MES 假期类型 MES_CAL_HOLIDAY_TYPE = 'mes_cal_holiday_type', // MES 假期类型
MES_TM_TOOL_STATUS = 'mes_tm_tool_status', // MES 工具状态
MES_TM_MAINTEN_TYPE = 'mes_tm_mainten_type' // MES 保养维护类型
} }

View File

@ -8,13 +8,13 @@
label-width="80px" label-width="80px"
v-loading="formLoading" v-loading="formLoading"
> >
<el-form-item label="日期" prop="theDay"> <el-form-item label="日期" prop="day">
<el-input v-model="formData.theDayDisplay" readonly /> <el-input :model-value="dayDisplay" readonly />
</el-form-item> </el-form-item>
<el-form-item label="类型" prop="type"> <el-form-item label="类型" prop="type">
<el-radio-group v-model="formData.type"> <el-radio-group v-model="formData.type">
<el-radio <el-radio
v-for="dict in getStrDictOptions(DICT_TYPE.MES_CAL_HOLIDAY_TYPE)" v-for="dict in getIntDictOptions(DICT_TYPE.MES_CAL_HOLIDAY_TYPE)"
:key="dict.value" :key="dict.value"
:value="dict.value" :value="dict.value"
> >
@ -22,6 +22,9 @@
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="formData.remark" type="textarea" :rows="3" placeholder="请输入备注" />
</el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button> <el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
@ -30,8 +33,10 @@
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { CalHolidayApi } from '@/api/mes/cal/holiday' import { CalHolidayApi } from '@/api/mes/cal/holiday'
import { formatDate } from '@/utils/formatTime'
import { HolidayType } from '@/views/mes/utils/constants'
defineOptions({ name: 'HolidayForm' }) defineOptions({ name: 'HolidayForm' })
@ -39,10 +44,11 @@ const message = useMessage()
const dialogVisible = ref(false) const dialogVisible = ref(false)
const formLoading = ref(false) const formLoading = ref(false)
const dayDisplay = ref('') // yyyy-MM-dd
const formData = ref({ const formData = ref({
theDay: '' as string, // yyyy-MM-dd 00:00:00 day: undefined as number | undefined, //
theDayDisplay: '' as string, // type: HolidayType.WORKDAY as number, //
type: 'HOLIDAY' as string remark: '' as string
}) })
const formRules = reactive({ const formRules = reactive({
type: [{ required: true, message: '请选择类型', trigger: 'change' }] type: [{ required: true, message: '请选择类型', trigger: 'change' }]
@ -50,13 +56,22 @@ const formRules = reactive({
const formRef = ref() const formRef = ref()
/** 打开弹窗 */ /** 打开弹窗 */
const open = (day: string) => { const open = async (day: string) => {
dialogVisible.value = true dialogVisible.value = true
resetForm() resetForm()
formData.value.theDayDisplay = day dayDisplay.value = day
// theDay datetime yyyy-MM-dd 00:00:00 formData.value.day = new Date(day + ' 00:00:00').getTime()
// TODO @ formLoading.value = true
formData.value.theDay = day + ' 00:00:00' //
try {
const data = await CalHolidayApi.getHolidayByDay(formatDate(formData.value.day as any))
if (data) {
formData.value.type = data.type ?? HolidayType.WORKDAY
formData.value.remark = data.remark ?? ''
}
} finally {
formLoading.value = false
}
} }
defineExpose({ open }) defineExpose({ open })
@ -66,7 +81,7 @@ const submitForm = async () => {
await formRef.value.validate() await formRef.value.validate()
formLoading.value = true formLoading.value = true
try { try {
await CalHolidayApi.createHoliday(formData.value as any) await CalHolidayApi.saveHoliday(formData.value as any)
message.success('设置成功') message.success('设置成功')
dialogVisible.value = false dialogVisible.value = false
emit('success') emit('success')
@ -78,10 +93,11 @@ const submitForm = async () => {
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { formData.value = {
theDay: '', day: undefined,
theDayDisplay: '', type: HolidayType.WORKDAY,
type: 'HOLIDAY' remark: ''
} }
dayDisplay.value = ''
formRef.value?.resetFields() formRef.value?.resetFields()
} }
</script> </script>

View File

@ -1,7 +1,6 @@
<!-- MES 假期设置 - 日历视图 --> <!-- MES 假期设置 - 日历视图 -->
<template> <template>
<ContentWrap> <ContentWrap>
<!-- TODO @AI从周一到周日这样的视图 -->
<el-calendar v-model="currentDate"> <el-calendar v-model="currentDate">
<template #date-cell="{ data }"> <template #date-cell="{ data }">
<div class="calendar-cell" @contextmenu.prevent="onRightClick(data)"> <div class="calendar-cell" @contextmenu.prevent="onRightClick(data)">
@ -9,24 +8,15 @@
<span class="solar-day" :class="{ weekend: isWeekend(data.day) }"> <span class="solar-day" :class="{ weekend: isWeekend(data.day) }">
{{ data.day.split('-')[2] }} {{ data.day.split('-')[2] }}
</span> </span>
<el-tag <el-tag v-if="holidaySet.has(data.day)" size="small" effect="dark" type="success">
v-if="holidaySet.has(data.day)"
size="small"
effect="dark"
type="success"
>
</el-tag> </el-tag>
<el-tag <el-tag v-else size="small" effect="dark"> </el-tag>
v-else-if="workdaySet.has(data.day)"
size="small"
effect="dark"
type="primary"
>
</el-tag>
</div> </div>
<div class="lunar-day" :class="{ festival: hasFestival(data.day) }"> <div
class="text-12px text-#909399 mt-4px"
:class="{ 'text-#67c23a': hasFestival(data.day) }"
>
{{ getLunarDisplay(data.day) }} {{ getLunarDisplay(data.day) }}
</div> </div>
</div> </div>
@ -39,46 +29,46 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { CalHolidayApi, CalHolidayVO } from '@/api/mes/cal/holiday' import { CalHolidayApi, CalHolidayVO } from '@/api/mes/cal/holiday'
import { formatDate } from '@/utils/formatTime'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import 'dayjs/locale/zh-cn'
import PluginLunar from 'dayjs-plugin-lunar' import PluginLunar from 'dayjs-plugin-lunar'
import { SolarDay } from 'tyme4ts' import { SolarDay } from 'tyme4ts'
import HolidayForm from './HolidayForm.vue' import HolidayForm from './HolidayForm.vue'
import { checkPermi } from '@/utils/permission' import { checkPermi } from '@/utils/permission'
import { HolidayType } from '@/views/mes/utils/constants'
dayjs.locale('zh-cn')
dayjs.extend(PluginLunar) dayjs.extend(PluginLunar)
defineOptions({ name: 'MesCalHoliday' }) defineOptions({ name: 'MesCalHoliday' })
const message = useMessage() const message = useMessage()
const currentDate = ref(new Date()) const currentDate = ref(new Date())
const holidaySet = ref(new Set<string>()) // HOLIDAY const holidaySet = ref(new Set<string>()) //
const workdaySet = ref(new Set<string>()) // WORKDAY
const formRef = ref() const formRef = ref()
/** 获取假期列表 */ /** 获取假期列表 */
const getList = async () => { const getList = async () => {
holidaySet.value.clear() holidaySet.value.clear()
workdaySet.value.clear()
const list = await CalHolidayApi.getHolidayList() const list = await CalHolidayApi.getHolidayList()
if (list) { if (list) {
list.forEach((item: CalHolidayVO) => { list.forEach((item: CalHolidayVO) => {
// theDay datetime 10 yyyy-MM-dd // day long yyyy-MM-dd
const day = item.theDay ? item.theDay.substring(0, 10) : '' const day = item.day ? formatDate(item.day as any, 'YYYY-MM-DD') : ''
if (!day) { if (day && item.type === HolidayType.HOLIDAY) {
return
}
if (item.type === 'HOLIDAY') {
holidaySet.value.add(day) holidaySet.value.add(day)
} else if (item.type === 'WORKDAY') {
workdaySet.value.add(day)
} }
}) })
} }
} }
/** 右键点击日期 */ /** 点击日期 */
const onRightClick = (data: { day: string }) => { const onClickDay = (data: { type: string; day: string }) => {
// //
if (data.type !== 'current-month') {
return
}
if (!checkPermi(['mes:cal-holiday:create'])) { if (!checkPermi(['mes:cal-holiday:create'])) {
message.warning('没有假期设置权限') message.warning('没有假期设置权限')
return return
@ -96,14 +86,14 @@ const isWeekend = (day: string): boolean => {
/** 获取农历显示信息 */ /** 获取农历显示信息 */
const getLunarInfo = (day: string) => { const getLunarInfo = (day: string) => {
const parts = day.split('-') const parts = day.split('-')
const y = parseInt(parts[0]), m = parseInt(parts[1]), d = parseInt(parts[2]) const year = parseInt(parts[0])
const month = parseInt(parts[1])
const date = parseInt(parts[2])
try { try {
const solarDay = SolarDay.fromYmd(y, m, d) const solarDay = SolarDay.fromYmd(year, month, date)
const lunarDay = solarDay.getLunarDay() const lunarDay = solarDay.getLunarDay()
// const solarFestival = solarDay.getFestival() //
const solarFestival = solarDay.getFestival() const lunarFestival = lunarDay.getFestival() //
//
const lunarFestival = lunarDay.getFestival()
// dayIndex === 0 // dayIndex === 0
const termDay = solarDay.getTermDay() const termDay = solarDay.getTermDay()
const termName = termDay.getDayIndex() === 0 ? termDay.getSolarTerm().getName() : null const termName = termDay.getDayIndex() === 0 ? termDay.getSolarTerm().getName() : null
@ -138,36 +128,4 @@ const hasFestival = (day: string): boolean => {
onMounted(() => { onMounted(() => {
getList() getList()
}) })
// TODO @AI使 unocss style
</script> </script>
<style scoped>
.calendar-cell {
height: 100%;
padding: 4px;
}
.calendar-cell-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.solar-day {
font-size: 16px;
font-weight: 500;
}
.solar-day.weekend {
color: #f56c6c;
}
.lunar-day {
font-size: 12px;
color: #909399;
margin-top: 4px;
}
.lunar-day.festival {
color: #67c23a;
}
</style>

View File

@ -10,6 +10,12 @@ export const MesItemOrProductEnum = {
} }
} as const } as const
/** MES 假期类型枚举 */
export const HolidayType = {
WORKDAY: 1, // 工作日
HOLIDAY: 2 // 节假日
} as const
/** 获取物料/产品标识的标签 */ /** 获取物料/产品标识的标签 */
export const getItemOrProductLabel = (value: string): string => { export const getItemOrProductLabel = (value: string): string => {
for (const item of Object.values(MesItemOrProductEnum)) { for (const item of Object.values(MesItemOrProductEnum)) {