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)) {