From 0c4ee24dd3f4e782e1ef6899990094eab230d01d Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 4 Apr 2026 20:07:56 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(mes):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=94=9F=E4=BA=A7=E6=B5=81=E8=BD=AC=E5=8D=A1=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加状态字段到 MesProCardRespVO 和相关的前端组件 - 实现提交、执行和取消生产流转卡的 API 接口 - 更新 MesProCardService 和 MesProCardServiceImpl 以支持新功能 - 更新前端表单和列表以显示和操作流转卡状态 --- src/api/mes/pro/card/index.ts | 16 +++ src/views/mes/pro/card/CardForm.vue | 149 +++++++++++++++------ src/views/mes/pro/card/CardProcessList.vue | 17 ++- src/views/mes/pro/card/index.vue | 54 ++++++-- src/views/mes/utils/constants.ts | 8 ++ 5 files changed, 192 insertions(+), 52 deletions(-) diff --git a/src/api/mes/pro/card/index.ts b/src/api/mes/pro/card/index.ts index d3c870113..625675b0e 100644 --- a/src/api/mes/pro/card/index.ts +++ b/src/api/mes/pro/card/index.ts @@ -14,6 +14,7 @@ export interface ProCardVO { specification: string // 规格型号 unitMeasureName: string // 单位名称 transferedQuantity: number // 流转数量 + status: number // 状态 remark: string // 备注 } @@ -49,6 +50,21 @@ export const ProCardApi = { return await request.download({ url: `/mes/pro/card/export-excel`, params }) }, + // 提交生产流转卡 + submitCard: async (id: number) => { + return await request.put({ url: `/mes/pro/card/submit?id=` + id }) + }, + + // 执行生产流转卡 + executeCard: async (id: number) => { + return await request.put({ url: `/mes/pro/card/execute?id=` + id }) + }, + + // 取消生产流转卡 + cancelCard: async (id: number) => { + return await request.put({ url: `/mes/pro/card/cancel?id=` + id }) + }, + // 获取生产流转卡精简列表 getCardSimpleList: async () => { return await request.get({ url: `/mes/pro/card/simple-list` }) diff --git a/src/views/mes/pro/card/CardForm.vue b/src/views/mes/pro/card/CardForm.vue index 7da4f6ab8..aa9fee438 100644 --- a/src/views/mes/pro/card/CardForm.vue +++ b/src/views/mes/pro/card/CardForm.vue @@ -7,11 +7,16 @@ :rules="formRules" label-width="120px" v-loading="formLoading" + :disabled="isDetail" > - + @@ -20,14 +25,14 @@ - + - + @@ -37,7 +42,7 @@ :min="0" :precision="2" class="!w-1/1" - :disabled="isDetail" + :disabled="isHeaderReadonly" /> @@ -46,7 +51,7 @@ @@ -58,21 +63,33 @@ type="textarea" v-model="formData.remark" placeholder="请输入备注" - :disabled="isDetail" + :disabled="isHeaderReadonly" /> - - - - - - - @@ -83,25 +100,37 @@ import { generateRandomStr } from '@/utils' import MdItemSelect from '@/views/mes/md/item/components/MdItemSelect.vue' import ProWorkOrderSelect from '@/views/mes/pro/workorder/components/ProWorkOrderSelect.vue' import CardProcessList from './CardProcessList.vue' +import { MesProCardStatusEnum } from '@/views/mes/utils/constants' defineOptions({ name: 'CardForm' }) +const emit = defineEmits(['success']) -const { t } = useI18n() // 国际化 const message = useMessage() // 消息弹窗 - const dialogVisible = ref(false) // 弹窗的是否展示 -const dialogTitle = ref('') // 弹窗的标题 const formLoading = ref(false) // 表单的加载中 -const formType = ref('') // 表单的类型:create - 新增;update - 修改;detail - 详情 -const activeTab = ref('process') // 活跃的 Tab +const formType = ref('create') // 表单的类型:create / update / execute / detail +const isEditable = computed(() => ['create', 'update'].includes(formType.value)) // 是否为编辑模式 +const isExecute = computed(() => formType.value === 'execute') // 是否为执行模式 +const isDetail = computed(() => ['detail', 'execute'].includes(formType.value)) // 是否为详情模式(表单只读) +const isHeaderReadonly = computed(() => ['execute', 'detail'].includes(formType.value)) // 头部是否只读 +const dialogTitle = computed(() => { + const titles: Record = { + create: '新增流转卡', + update: '编辑流转卡', + execute: '执行流转卡', + detail: '流转卡详情' + } + return titles[formType.value] || formType.value +}) const formData = ref({ - id: undefined, - code: undefined, - workOrderId: undefined, - batchCode: undefined, - itemId: undefined, - transferedQuantity: undefined, - remark: undefined + id: undefined as number | undefined, + code: undefined as string | undefined, + workOrderId: undefined as number | undefined, + batchCode: undefined as string | undefined, + itemId: undefined as number | undefined, + transferedQuantity: undefined as number | undefined, + status: undefined as number | undefined, + remark: undefined as string | undefined }) const formRules = reactive({ code: [{ required: true, message: '流转卡编码不能为空', trigger: 'blur' }], @@ -110,9 +139,7 @@ const formRules = reactive({ transferedQuantity: [{ required: true, message: '流转数量不能为空', trigger: 'blur' }] }) const formRef = ref() // 表单 Ref - -/** 是否为详情模式 */ -const isDetail = computed(() => formType.value === 'detail') +const originalFormData = ref('') // 原始表单数据快照,用于脏检查 /** 生成流转卡编码 */ const generateCode = () => { @@ -122,11 +149,9 @@ const generateCode = () => { /** 打开弹窗 */ const open = async (type: string, id?: number) => { dialogVisible.value = true - dialogTitle.value = type === 'detail' ? '流转卡详情' : t('action.' + type) formType.value = type - activeTab.value = 'process' resetForm() - // 修改/详情时,设置数据 + // 修改/执行/详情时,加载数据 if (id) { formLoading.value = true try { @@ -135,26 +160,67 @@ const open = async (type: string, id?: number) => { formLoading.value = false } } + // 保存原始数据快照 + originalFormData.value = JSON.stringify(formData.value) } -defineExpose({ open }) // 提供 open 方法,用于打开弹窗 - -/** 提交表单 */ -const emit = defineEmits(['success']) +/** 提交表单(create/update 模式) */ const submitForm = async () => { await formRef.value.validate() formLoading.value = true try { const data = formData.value as unknown as ProCardVO if (formType.value === 'create') { - await ProCardApi.createCard(data) - message.success(t('common.createSuccess')) + const res = await ProCardApi.createCard(data) + message.success('新增成功') + // 创建成功后,更新表单数据和状态为编辑模式 + formData.value.id = res + formData.value.status = MesProCardStatusEnum.PREPARE + formType.value = 'update' } else { await ProCardApi.updateCard(data) - message.success(t('common.updateSuccess')) + message.success('修改成功') } + // 更新快照 + originalFormData.value = JSON.stringify(formData.value) + emit('success') + } finally { + formLoading.value = false + } +} + +/** 提交操作:表单修改过则先保存,再提交 */ +const handleSubmit = async () => { + await formRef.value.validate() + try { + await message.confirm('确认提交该流转卡?【提交后将不能修改】') + formLoading.value = true + // 1. 表单有修改时,先保存 + if (JSON.stringify(formData.value) !== originalFormData.value) { + const data = formData.value as unknown as ProCardVO + await ProCardApi.updateCard(data) + } + // 2. 提交流转卡 + await ProCardApi.submitCard(formData.value.id!) + message.success('提交成功') dialogVisible.value = false emit('success') + } catch { + } finally { + formLoading.value = false + } +} + +/** 执行流转卡 */ +const handleExecute = async () => { + try { + await message.confirm('确认执行该流转卡?') + formLoading.value = true + await ProCardApi.executeCard(formData.value.id!) + message.success('执行成功') + dialogVisible.value = false + emit('success') + } catch { } finally { formLoading.value = false } @@ -169,8 +235,11 @@ const resetForm = () => { batchCode: undefined, itemId: undefined, transferedQuantity: undefined, + status: undefined, remark: undefined } formRef.value?.resetFields() } + +defineExpose({ open }) diff --git a/src/views/mes/pro/card/CardProcessList.vue b/src/views/mes/pro/card/CardProcessList.vue index ad35b5789..659d568d9 100644 --- a/src/views/mes/pro/card/CardProcessList.vue +++ b/src/views/mes/pro/card/CardProcessList.vue @@ -133,6 +133,11 @@ + + + + + @@ -143,9 +148,9 @@ @@ -157,6 +162,7 @@ import { dateFormatter } from '@/utils/formatTime' import { ProCardProcessApi, ProCardProcessVO } from '@/api/mes/pro/card/process' import ProProcessSelect from '@/views/mes/pro/process/components/ProProcessSelect.vue' import MdWorkstationSelect from '@/views/mes/md/workstation/components/MdWorkstationSelect.vue' +import UserSelect from '@/views/system/user/components/UserSelect.vue' defineOptions({ name: 'CardProcessList' }) @@ -201,7 +207,7 @@ const handleDelete = async (id: number) => { } catch {} } -// ==================== 工序记录编辑表单(内联) ==================== +// ==================== 工序记录编辑表单 ==================== const processDialogVisible = ref(false) const processDialogTitle = ref('') const processFormLoading = ref(false) @@ -217,6 +223,7 @@ const processFormData = ref({ outputQuantity: undefined as number | undefined, unqualifiedQuantity: undefined as number | undefined, workstationId: undefined as number | undefined, + userId: undefined as number | undefined, remark: undefined as string | undefined }) const processFormRules = reactive({}) @@ -237,6 +244,7 @@ const openProcessForm = (type: string, row?: any) => { outputQuantity: undefined, unqualifiedQuantity: undefined, workstationId: undefined, + userId: undefined, remark: undefined } } else { @@ -251,6 +259,7 @@ const openProcessForm = (type: string, row?: any) => { outputQuantity: row.outputQuantity, unqualifiedQuantity: row.unqualifiedQuantity, workstationId: row.workstationId, + userId: row.userId, remark: row.remark } } diff --git a/src/views/mes/pro/card/index.vue b/src/views/mes/pro/card/index.vue index 2faf7e0e3..2a3377f56 100644 --- a/src/views/mes/pro/card/index.vue +++ b/src/views/mes/pro/card/index.vue @@ -37,7 +37,6 @@ class="!w-240px" /> - 搜索 重置 @@ -80,14 +79,20 @@ - + + + + @@ -116,11 +141,13 @@ diff --git a/src/views/mes/utils/constants.ts b/src/views/mes/utils/constants.ts index 49cce4665..acb74040e 100644 --- a/src/views/mes/utils/constants.ts +++ b/src/views/mes/utils/constants.ts @@ -66,6 +66,14 @@ export const MesProWorkOrderStatusEnum = { CANCELED: 3 // 已取消 } +/** MES 生产流转卡状态枚举(复用工单状态值) */ +export const MesProCardStatusEnum = { + PREPARE: 0, // 草稿 + CONFIRMED: 1, // 已确认 + FINISHED: 2, // 已完成 + CANCELED: 3 // 已取消 +} + /** MES 工单类型枚举 */ export const MesProWorkOrderTypeEnum = { SELF: 1, // 自行生产