From 79af870afef470a85a5ecb256c0746962b47481f Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 May 2026 09:16:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(mes):=20=E6=8F=90=E4=BA=A4=20wm=20outsourc?= =?UTF-8?q?e=20=E7=9B=B8=E5=85=B3=E7=9A=84=E8=BF=81=E7=A7=BB=EF=BC=88?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/mes/pro/card/index.ts | 35 ++ .../src/api/mes/pro/card/process/index.ts | 62 +++ apps/web-antd/src/api/mes/pro/task/index.ts | 27 ++ .../src/api/mes/pro/workorder/bom/index.ts | 62 +++ .../src/api/mes/pro/workorder/index.ts | 84 +++- .../api/mes/wm/outsourcereceipt/line/index.ts | 1 + .../web-antd/src/router/routes/modules/mes.ts | 9 + .../web-antd/src/views/mes/utils/constants.ts | 6 + .../mes/wm/outsourceissue/modules/form.vue | 29 +- .../wm/outsourceissue/modules/line-list.vue | 5 +- .../outsourcereceipt/modules/detail-list.vue | 7 +- .../mes/wm/outsourcereceipt/modules/form.vue | 28 +- .../wm/outsourcereceipt/modules/line-form.vue | 1 - .../wm/outsourcereceipt/modules/line-list.vue | 4 +- .../stocktaking/plan/modules/param-list.vue | 131 ++++++ .../api/mes/wm/outsourcereceipt/line/index.ts | 1 + apps/web-ele/src/views/mes/pro/card/data.ts | 424 +++++++++++++++++- .../mes/pro/workorder/components/index.ts | 1 + .../components/pro-work-order-select.vue | 192 ++++---- .../mes/wm/outsourceissue/modules/form.vue | 27 +- .../wm/outsourceissue/modules/line-list.vue | 4 +- .../outsourcereceipt/modules/detail-list.vue | 6 +- .../mes/wm/outsourcereceipt/modules/form.vue | 27 +- .../wm/outsourcereceipt/modules/line-list.vue | 4 +- 24 files changed, 970 insertions(+), 207 deletions(-) create mode 100644 apps/web-antd/src/api/mes/pro/card/process/index.ts create mode 100644 apps/web-antd/src/api/mes/pro/workorder/bom/index.ts create mode 100644 apps/web-antd/src/views/mes/wm/stocktaking/plan/modules/param-list.vue diff --git a/apps/web-antd/src/api/mes/pro/card/index.ts b/apps/web-antd/src/api/mes/pro/card/index.ts index 06c6cb04f..a9d123cc3 100644 --- a/apps/web-antd/src/api/mes/pro/card/index.ts +++ b/apps/web-antd/src/api/mes/pro/card/index.ts @@ -42,3 +42,38 @@ export function getCardPage(params: MesProCardApi.PageParams) { export function getCard(id: number) { return requestClient.get(`/mes/pro/card/get?id=${id}`); } + +/** 新增生产流转卡 */ +export function createCard(data: MesProCardApi.Card) { + return requestClient.post('/mes/pro/card/create', data); +} + +/** 修改生产流转卡 */ +export function updateCard(data: MesProCardApi.Card) { + return requestClient.put('/mes/pro/card/update', data); +} + +/** 删除生产流转卡 */ +export function deleteCard(id: number) { + return requestClient.delete(`/mes/pro/card/delete?id=${id}`); +} + +/** 导出生产流转卡 */ +export function exportCard(params: any) { + return requestClient.download('/mes/pro/card/export-excel', { params }); +} + +/** 提交生产流转卡 */ +export function submitCard(id: number) { + return requestClient.put(`/mes/pro/card/submit?id=${id}`); +} + +/** 完成生产流转卡 */ +export function finishCard(id: number) { + return requestClient.put(`/mes/pro/card/finish?id=${id}`); +} + +/** 取消生产流转卡 */ +export function cancelCard(id: number) { + return requestClient.put(`/mes/pro/card/cancel?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/card/process/index.ts b/apps/web-antd/src/api/mes/pro/card/process/index.ts new file mode 100644 index 000000000..a6f372fe2 --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/card/process/index.ts @@ -0,0 +1,62 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProCardProcessApi { + /** MES 流转卡工序记录 */ + export interface CardProcess { + id?: number; // 编号 + cardId?: number; // 流转卡编号 + sort?: number; // 序号 + processId?: number; // 工序编号 + processCode?: string; // 工序编码 + processName?: string; // 工序名称 + inputTime?: number; // 进入工序时间 + outputTime?: number; // 出工序时间 + inputQuantity?: number; // 投入数量 + outputQuantity?: number; // 产出数量 + unqualifiedQuantity?: number; // 不合格品数量 + workstationId?: number; // 工位编号 + workstationCode?: string; // 工位编码 + workstationName?: string; // 工位名称 + userId?: number; // 操作人编号 + nickname?: string; // 操作人名称 + ipqcId?: number; // 过程检验单编号 + remark?: string; // 备注 + } + + /** MES 流转卡工序记录分页查询参数 */ + export interface PageParams extends PageParam { + cardId?: number; + } +} + +/** 查询流转卡工序记录分页 */ +export function getCardProcessPage(params: MesProCardProcessApi.PageParams) { + return requestClient.get>( + '/mes/pro/card-process/page', + { params }, + ); +} + +/** 查询流转卡工序记录详情 */ +export function getCardProcess(id: number) { + return requestClient.get( + `/mes/pro/card-process/get?id=${id}`, + ); +} + +/** 新增流转卡工序记录 */ +export function createCardProcess(data: MesProCardProcessApi.CardProcess) { + return requestClient.post('/mes/pro/card-process/create', data); +} + +/** 修改流转卡工序记录 */ +export function updateCardProcess(data: MesProCardProcessApi.CardProcess) { + return requestClient.put('/mes/pro/card-process/update', data); +} + +/** 删除流转卡工序记录 */ +export function deleteCardProcess(id: number) { + return requestClient.delete(`/mes/pro/card-process/delete?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/pro/task/index.ts b/apps/web-antd/src/api/mes/pro/task/index.ts index d7bfd2f5e..5e160c840 100644 --- a/apps/web-antd/src/api/mes/pro/task/index.ts +++ b/apps/web-antd/src/api/mes/pro/task/index.ts @@ -48,6 +48,8 @@ export namespace MesProTaskApi { name?: string; workOrderId?: number; workstationId?: number; + routeId?: number; + processId?: number; itemId?: number; statuses?: number[]; status?: number; @@ -66,3 +68,28 @@ export function getTaskPage(params: MesProTaskApi.PageParams) { export function getTask(id: number) { return requestClient.get(`/mes/pro/task/get?id=${id}`); } + +/** 新增生产任务 */ +export function createTask(data: MesProTaskApi.Task) { + return requestClient.post('/mes/pro/task/create', data); +} + +/** 修改生产任务 */ +export function updateTask(data: MesProTaskApi.Task) { + return requestClient.put('/mes/pro/task/update', data); +} + +/** 删除生产任务 */ +export function deleteTask(id: number) { + return requestClient.delete(`/mes/pro/task/delete?id=${id}`); +} + +/** 导出生产任务 */ +export function exportTask(params: any) { + return requestClient.download('/mes/pro/task/export-excel', { params }); +} + +/** 查询甘特图任务列表(非分页) */ +export function getGanttTaskList(params: any) { + return requestClient.get('/mes/pro/task/gantt-list', { params }); +} diff --git a/apps/web-antd/src/api/mes/pro/workorder/bom/index.ts b/apps/web-antd/src/api/mes/pro/workorder/bom/index.ts new file mode 100644 index 000000000..f04ef761c --- /dev/null +++ b/apps/web-antd/src/api/mes/pro/workorder/bom/index.ts @@ -0,0 +1,62 @@ +import type { PageParam, PageResult } from '@vben/request'; + +import { requestClient } from '#/api/request'; + +export namespace MesProWorkOrderBomApi { + /** MES 生产工单 BOM */ + export interface WorkOrderBom { + id?: number; // 编号 + workOrderId?: number; // 生产工单编号 + itemId?: number; // BOM 物料编号 + itemName?: string; // 物料名称 + itemCode?: string; // 物料编码 + itemSpecification?: string; // 规格型号 + unitMeasureId?: number; // 单位编号 + unitMeasureName?: string; // 单位名称 + quantity?: number; // 预计使用量 + remark?: string; // 备注 + itemOrProduct?: string; // 物料产品标识 + } + + /** MES 生产工单 BOM 分页查询参数 */ + export interface PageParams extends PageParam { + workOrderId?: number; + } +} + +/** 查询工单 BOM 分页 */ +export function getWorkOrderBomPage(params: MesProWorkOrderBomApi.PageParams) { + return requestClient.get>( + '/mes/pro/work-order-bom/page', + { params }, + ); +} + +/** 查询工单 BOM 详情 */ +export function getWorkOrderBom(id: number) { + return requestClient.get( + `/mes/pro/work-order-bom/get?id=${id}`, + ); +} + +/** 新增工单 BOM */ +export function createWorkOrderBom(data: MesProWorkOrderBomApi.WorkOrderBom) { + return requestClient.post('/mes/pro/work-order-bom/create', data); +} + +/** 修改工单 BOM */ +export function updateWorkOrderBom(data: MesProWorkOrderBomApi.WorkOrderBom) { + return requestClient.put('/mes/pro/work-order-bom/update', data); +} + +/** 删除工单 BOM */ +export function deleteWorkOrderBom(id: number) { + return requestClient.delete(`/mes/pro/work-order-bom/delete?id=${id}`); +} + +/** 查询工单物料需求列表 */ +export function getWorkOrderBomItemListByWorkOrderId(workOrderId: number) { + return requestClient.get( + `/mes/pro/work-order-bom/item-list-by-work-order-id?workOrderId=${workOrderId}`, + ); +} diff --git a/apps/web-antd/src/api/mes/pro/workorder/index.ts b/apps/web-antd/src/api/mes/pro/workorder/index.ts index 24de7d057..c4c0a152a 100644 --- a/apps/web-antd/src/api/mes/pro/workorder/index.ts +++ b/apps/web-antd/src/api/mes/pro/workorder/index.ts @@ -5,37 +5,48 @@ import { requestClient } from '#/api/request'; export namespace MesProWorkOrderApi { /** MES 生产工单 */ export interface WorkOrder { - id?: number; + id?: number; // 编号 code?: string; // 工单编码 name?: string; // 工单名称 type?: number; // 工单类型 - status?: number; // 工单状态 - sourceType?: number; - productId?: number; // 产品物料编号 - productCode?: string; - productName?: string; - productSpecification?: string; - quantity?: number; - unitName?: string; - routeId?: number; - routeName?: string; - clientId?: number; - clientName?: string; + orderSourceType?: number; // 来源类型 + orderSourceCode?: string; // 来源单据编号 + productId?: number; // 产品编号 + productName?: string; // 产品名称 + productCode?: string; // 产品编码 + productSpecification?: string; // 规格型号 + unitMeasureName?: string; // 单位名称 + quantity?: number; // 生产数量 + quantityProduced?: number; // 已生产数量 + quantityChanged?: number; // 调整数量 + quantityScheduled?: number; // 已排产数量 + clientId?: number; // 客户编号 + clientCode?: string; // 客户编码 + clientName?: string; // 客户名称 vendorId?: number; // 供应商编号 vendorName?: string; // 供应商名称 - planStartTime?: number | string; - planEndTime?: number | string; - actualStartTime?: number | string; - actualEndTime?: number | string; - remark?: string; - createTime?: number | string; + vendorCode?: string; // 供应商编码 + batchCode?: string; // 批次号 + requestDate?: number; // 需求日期 + parentId?: number; // 父工单编号 + parentCode?: string; // 父工单编码 + finishDate?: number; // 完成时间 + cancelDate?: number; // 取消时间 + status?: number; // 工单状态 + remark?: string; // 备注 + createTime?: number; // 创建时间 } + /** MES 生产工单分页查询参数 */ export interface PageParams extends PageParam { code?: string; name?: string; + orderSourceCode?: string; + productId?: number; + clientId?: number; status?: number; type?: number; + requestDate?: number[]; } } @@ -53,3 +64,38 @@ export function getWorkOrder(id: number) { `/mes/pro/work-order/get?id=${id}`, ); } + +/** 新增生产工单 */ +export function createWorkOrder(data: MesProWorkOrderApi.WorkOrder) { + return requestClient.post('/mes/pro/work-order/create', data); +} + +/** 修改生产工单 */ +export function updateWorkOrder(data: MesProWorkOrderApi.WorkOrder) { + return requestClient.put('/mes/pro/work-order/update', data); +} + +/** 删除生产工单 */ +export function deleteWorkOrder(id: number) { + return requestClient.delete(`/mes/pro/work-order/delete?id=${id}`); +} + +/** 导出生产工单 */ +export function exportWorkOrder(params: any) { + return requestClient.download('/mes/pro/work-order/export-excel', { params }); +} + +/** 完成工单 */ +export function finishWorkOrder(id: number) { + return requestClient.put(`/mes/pro/work-order/finish?id=${id}`); +} + +/** 取消工单 */ +export function cancelWorkOrder(id: number) { + return requestClient.put(`/mes/pro/work-order/cancel?id=${id}`); +} + +/** 确认工单 */ +export function confirmWorkOrder(id: number) { + return requestClient.put(`/mes/pro/work-order/confirm?id=${id}`); +} diff --git a/apps/web-antd/src/api/mes/wm/outsourcereceipt/line/index.ts b/apps/web-antd/src/api/mes/wm/outsourcereceipt/line/index.ts index fd5c0ce46..d28412a5b 100644 --- a/apps/web-antd/src/api/mes/wm/outsourcereceipt/line/index.ts +++ b/apps/web-antd/src/api/mes/wm/outsourcereceipt/line/index.ts @@ -19,6 +19,7 @@ export namespace MesWmOutsourceReceiptLineApi { expireDate?: number; // 有效期 lotNumber?: string; // 生产批号 iqcCheckFlag?: boolean; // 是否需要质检 + qualityStatus?: number; // 质量状态 remark?: string; // 备注 createTime?: Date; // 创建时间 } diff --git a/apps/web-antd/src/router/routes/modules/mes.ts b/apps/web-antd/src/router/routes/modules/mes.ts index 05af60e29..4172fdbc9 100644 --- a/apps/web-antd/src/router/routes/modules/mes.ts +++ b/apps/web-antd/src/router/routes/modules/mes.ts @@ -39,6 +39,15 @@ const routes: RouteRecordRaw[] = [ }, component: () => import('#/views/mes/wm/barcode/config/index.vue'), }, + { + path: 'pro/task/edit', + name: 'MesProTaskGanttEdit', + meta: { + title: '甘特图编辑', + activePath: '/mes/pro/task', + }, + component: () => import('#/views/mes/pro/task/edit/index.vue'), + }, ], }, ]; diff --git a/apps/web-antd/src/views/mes/utils/constants.ts b/apps/web-antd/src/views/mes/utils/constants.ts index 19315fc41..08b97af14 100644 --- a/apps/web-antd/src/views/mes/utils/constants.ts +++ b/apps/web-antd/src/views/mes/utils/constants.ts @@ -225,6 +225,12 @@ export const MesProWorkOrderTypeEnum = { PURCHASE: 3, // 采购 } as const; +/** MES 工单来源类型枚举 */ +export const MesProWorkOrderSourceTypeEnum = { + ORDER: 1, // 客户订单 + STORE: 2, // 库存备货 +} as const; + /** MES 生产任务状态枚举 */ export const MesProTaskStatusEnum = { PREPARE: MesOrderStatusConstants.DRAFT, diff --git a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/form.vue b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/form.vue index 160e932af..bbe1b8c25 100644 --- a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/form.vue +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/form.vue @@ -38,25 +38,19 @@ const canSubmit = computed(() => // 是否可提交 formType.value === 'update' && formData.value?.status === MesWmOutsourceIssueStatusEnum.PREPARE, ); -// TODO @AI:标题的代码风格; const getTitle = computed(() => { - switch (formType.value) { - case 'detail': { - return $t('ui.actionTitle.view', ['外协发料单']); - } - case 'finish': { - return '执行领出'; - } - case 'stock': { - return '执行拣货'; - } - case 'update': { - return $t('ui.actionTitle.edit', ['外协发料单']); - } - default: { - return $t('ui.actionTitle.create', ['外协发料单']); - } + if (formType.value === 'detail') { + return $t('ui.actionTitle.view', ['外协发料单']); } + if (formType.value === 'stock') { + return '执行拣货'; + } + if (formType.value === 'finish') { + return '执行领出'; + } + return formType.value === 'update' + ? $t('ui.actionTitle.edit', ['外协发料单']) + : $t('ui.actionTitle.create', ['外协发料单']); }); const [Form, formApi] = useVbenForm({ @@ -138,7 +132,6 @@ async function handleFinish() { } const [Modal, modalApi] = useVbenModal({ - // TODO @AI:方法注释,缺少“// 关闭并提示”;看看其他 form.vue 或者 xxx-form.vue 有没类似的情况; async onConfirm() { if (!isEditable.value) { await modalApi.close(); diff --git a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-list.vue index 30548696d..92a804dad 100644 --- a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-list.vue +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-list.vue @@ -27,10 +27,9 @@ const props = defineProps<{ issueId: number; }>(); -// TODO @AI:// 是否可编辑明细行 拿到 “computed(() =>”; -const isEditable = computed(() => +const isEditable = computed(() => // 是否可编辑明细行 ['create', 'update'].includes(props.formType), -); // 是否可编辑明细行 +); const isStock = computed(() => props.formType === 'stock'); // 是否为拣货模式 const detailMap = reactive< Record diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue index 8fc1718d9..c46d6a93b 100644 --- a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue @@ -22,10 +22,9 @@ const emit = defineEmits<{ refresh: []; }>(); -// TODO @AI:放到 “// 是否可维护收货明细(编辑或上架态)” 到 computed( 后面 -const isEditable = computed( - () => ['create', 'stock', 'update'].includes(props.formType), -); // 是否可维护收货明细(编辑或上架态) +const isEditable = computed(() => // 是否可维护收货明细(编辑或上架态) + ['create', 'stock', 'update'].includes(props.formType), +); /** 添加收货明细 */ function handleCreate() { diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/form.vue b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/form.vue index 76879cb67..d059dfd6a 100644 --- a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/form.vue +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/form.vue @@ -37,25 +37,19 @@ const canSubmit = computed(() => // 是否可提交 formType.value === 'update' && formData.value?.status === MesWmOutsourceReceiptStatusEnum.PREPARE, ); -// TODO @AI:方法的代码风格; const getTitle = computed(() => { - switch (formType.value) { - case 'detail': { - return $t('ui.actionTitle.view', ['外协入库单']); - } - case 'finish': { - return '完成入库'; - } - case 'stock': { - return '执行上架'; - } - case 'update': { - return $t('ui.actionTitle.edit', ['外协入库单']); - } - default: { - return $t('ui.actionTitle.create', ['外协入库单']); - } + if (formType.value === 'detail') { + return $t('ui.actionTitle.view', ['外协入库单']); } + if (formType.value === 'stock') { + return '执行上架'; + } + if (formType.value === 'finish') { + return '完成入库'; + } + return formType.value === 'update' + ? $t('ui.actionTitle.edit', ['外协入库单']) + : $t('ui.actionTitle.create', ['外协入库单']); }); const [Form, formApi] = useVbenForm({ diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-form.vue index e2b9d6541..f0a612c2f 100644 --- a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-form.vue +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-form.vue @@ -21,7 +21,6 @@ const emit = defineEmits(['success']); const formData = ref(); const receiptId = ref(); // 所属入库单编号 -// TODO @AI:如果 getTitle 方法的前面,也是 const 变量,不用空行?是不是更符合项目规范?如果是,写到 style vue 文件里; const getTitle = computed(() => { return formData.value?.id ? $t('ui.actionTitle.edit', ['外协入库单行']) diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-list.vue index 23e00bf2e..436291201 100644 --- a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-list.vue +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-list.vue @@ -28,9 +28,9 @@ const props = defineProps<{ receiptId: number; }>(); -const isEditable = computed(() => +const isEditable = computed(() => // 是否可编辑明细行 ['create', 'update'].includes(props.formType), -); // 是否可编辑明细行 +); const isStock = computed(() => props.formType === 'stock'); // 是否为上架模式 const detailMap = reactive< Record diff --git a/apps/web-antd/src/views/mes/wm/stocktaking/plan/modules/param-list.vue b/apps/web-antd/src/views/mes/wm/stocktaking/plan/modules/param-list.vue new file mode 100644 index 000000000..47df0986f --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/stocktaking/plan/modules/param-list.vue @@ -0,0 +1,131 @@ + + + diff --git a/apps/web-ele/src/api/mes/wm/outsourcereceipt/line/index.ts b/apps/web-ele/src/api/mes/wm/outsourcereceipt/line/index.ts index fd5c0ce46..d28412a5b 100644 --- a/apps/web-ele/src/api/mes/wm/outsourcereceipt/line/index.ts +++ b/apps/web-ele/src/api/mes/wm/outsourcereceipt/line/index.ts @@ -19,6 +19,7 @@ export namespace MesWmOutsourceReceiptLineApi { expireDate?: number; // 有效期 lotNumber?: string; // 生产批号 iqcCheckFlag?: boolean; // 是否需要质检 + qualityStatus?: number; // 质量状态 remark?: string; // 备注 createTime?: Date; // 创建时间 } diff --git a/apps/web-ele/src/views/mes/pro/card/data.ts b/apps/web-ele/src/views/mes/pro/card/data.ts index eefd623fa..1bab3d7fc 100644 --- a/apps/web-ele/src/views/mes/pro/card/data.ts +++ b/apps/web-ele/src/views/mes/pro/card/data.ts @@ -1,11 +1,431 @@ -import type { VbenFormSchema } from '#/adapter/form'; +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; import type { VxeTableGridOptions } from '#/adapter/vxe-table'; import type { MesProCardApi } from '#/api/mes/pro/card'; +import type { MesProCardProcessApi } from '#/api/mes/pro/card/process'; -import { markRaw } from 'vue'; +import { h, markRaw } from 'vue'; +import { DICT_TYPE } from '@vben/constants'; + +import { ElButton } from 'element-plus'; + +import { generateAutoCode } from '#/api/mes/md/autocode/record'; import { MdItemSelect } from '#/views/mes/md/item/components'; +import { MdWorkstationSelect } from '#/views/mes/md/workstation/components'; +import { ProProcessSelect } from '#/views/mes/pro/process/components'; import { ProWorkOrderSelect } from '#/views/mes/pro/workorder/components'; +import { + MesAutoCodeRuleCode, + MesProWorkOrderStatusEnum, +} from '#/views/mes/utils/constants'; +import { UserSelect } from '#/views/system/user/components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'finish' | 'update'; + +/** 表头是否只读(完成、详情态) */ +function isHeaderReadonly(formType: FormType): boolean { + return formType === 'detail' || formType === 'finish'; +} + +/** 新增/修改的表单 */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + const headerReadonly = isHeaderReadonly(formType); + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'status', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'code', + label: '流转卡编码', + component: 'Input', + componentProps: { + disabled: headerReadonly, + placeholder: '请输入流转卡编码', + }, + rules: 'required', + suffix: + formType === 'create' || formType === 'update' + ? () => + h( + ElButton, + { + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.PRO_CARD_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ) + : undefined, + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + disabled: headerReadonly, + placeholder: '请选择生产工单', + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + rules: 'selectRequired', + }, + { + fieldName: 'itemId', + label: '产品', + component: markRaw(MdItemSelect), + componentProps: { + disabled: headerReadonly, + placeholder: '请选择产品', + }, + rules: 'selectRequired', + }, + { + fieldName: 'transferedQuantity', + label: '流转数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + disabled: headerReadonly, + min: 0, + placeholder: '请输入流转数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: headerReadonly, + placeholder: '请输入批次号', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + disabled: headerReadonly, + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '流转卡编码', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入流转卡编码', + }, + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + placeholder: '请选择生产工单', + }, + }, + { + fieldName: 'itemId', + label: '产品', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择产品', + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入批次号', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '流转卡编码', + width: 160, + slots: { default: 'code' }, + }, + { + field: 'workOrderCode', + title: '生产工单编号', + width: 160, + }, + { + field: 'workOrderName', + title: '工单名称', + minWidth: 150, + }, + { + field: 'batchCode', + title: '批次号', + width: 120, + }, + { + field: 'itemCode', + title: '产品物料编码', + width: 140, + }, + { + field: 'itemName', + title: '产品物料名称', + minWidth: 120, + }, + { + field: 'specification', + title: '规格型号', + width: 120, + }, + { + field: 'unitMeasureName', + title: '单位', + width: 80, + }, + { + field: 'transferedQuantity', + title: '流转数量', + width: 100, + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_PRO_WORK_ORDER_STATUS }, + }, + }, + { + title: '操作', + width: 240, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 工序记录子表的字段 */ +export function useProcessGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'sort', + title: '序号', + width: 60, + }, + { + field: 'processName', + title: '工序名称', + minWidth: 120, + }, + { + field: 'processCode', + title: '工序编码', + width: 120, + }, + { + field: 'inputTime', + title: '进入工序时间', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'outputTime', + title: '出工序时间', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'inputQuantity', + title: '投入数量', + width: 100, + }, + { + field: 'outputQuantity', + title: '产出数量', + width: 100, + }, + { + field: 'unqualifiedQuantity', + title: '不良品数量', + width: 100, + }, + { + field: 'workstationCode', + title: '工位编码', + width: 120, + }, + { + field: 'workstationName', + title: '工位名称', + minWidth: 120, + }, + { + field: 'nickname', + title: '操作人', + width: 100, + }, + ...(editable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 工序记录新增/修改的表单 */ +export function useProcessFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'sort', + label: '序号', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入序号', + precision: 0, + }, + }, + { + fieldName: 'processId', + label: '工序', + component: markRaw(ProProcessSelect), + componentProps: { + placeholder: '请选择工序', + }, + }, + { + fieldName: 'inputTime', + label: '进入工序时间', + component: 'DatePicker', + componentProps: { + class: '!w-full', + placeholder: '请选择进入工序时间', + type: 'datetime', + valueFormat: 'x', + }, + }, + { + fieldName: 'outputTime', + label: '出工序时间', + component: 'DatePicker', + componentProps: { + class: '!w-full', + placeholder: '请选择出工序时间', + type: 'datetime', + valueFormat: 'x', + }, + }, + { + fieldName: 'inputQuantity', + label: '投入数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入投入数量', + precision: 2, + }, + }, + { + fieldName: 'outputQuantity', + label: '产出数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入产出数量', + precision: 2, + }, + }, + { + fieldName: 'unqualifiedQuantity', + label: '不合格数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入不合格数量', + precision: 2, + }, + }, + { + fieldName: 'workstationId', + label: '工位', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工位', + }, + }, + { + fieldName: 'userId', + label: '操作人', + component: markRaw(UserSelect), + componentProps: { + placeholder: '请选择操作人', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} /** 流转卡选择弹窗的搜索表单 */ export function useCardSelectGridFormSchema(): VbenFormSchema[] { diff --git a/apps/web-ele/src/views/mes/pro/workorder/components/index.ts b/apps/web-ele/src/views/mes/pro/workorder/components/index.ts index 1059f8a79..b53e2876b 100644 --- a/apps/web-ele/src/views/mes/pro/workorder/components/index.ts +++ b/apps/web-ele/src/views/mes/pro/workorder/components/index.ts @@ -1 +1,2 @@ +export { default as ProWorkOrderSelectDialog } from './pro-work-order-select-dialog.vue'; export { default as ProWorkOrderSelect } from './pro-work-order-select.vue'; diff --git a/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue b/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue index d02e67dd9..affb6907d 100644 --- a/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue +++ b/apps/web-ele/src/views/mes/pro/workorder/components/pro-work-order-select.vue @@ -1,20 +1,16 @@ diff --git a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/form.vue b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/form.vue index 708935fa0..0aa12cf93 100644 --- a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/form.vue +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/form.vue @@ -39,23 +39,18 @@ const canSubmit = computed(() => // 是否可提交 formData.value?.status === MesWmOutsourceIssueStatusEnum.PREPARE, ); const getTitle = computed(() => { - switch (formType.value) { - case 'detail': { - return $t('ui.actionTitle.view', ['外协发料单']); - } - case 'finish': { - return '执行领出'; - } - case 'stock': { - return '执行拣货'; - } - case 'update': { - return $t('ui.actionTitle.edit', ['外协发料单']); - } - default: { - return $t('ui.actionTitle.create', ['外协发料单']); - } + if (formType.value === 'detail') { + return $t('ui.actionTitle.view', ['外协发料单']); } + if (formType.value === 'stock') { + return '执行拣货'; + } + if (formType.value === 'finish') { + return '执行领出'; + } + return formType.value === 'update' + ? $t('ui.actionTitle.edit', ['外协发料单']) + : $t('ui.actionTitle.create', ['外协发料单']); }); const [Form, formApi] = useVbenForm({ diff --git a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-list.vue index a8ba2b4f3..d8144aaad 100644 --- a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-list.vue +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-list.vue @@ -27,9 +27,9 @@ const props = defineProps<{ issueId: number; }>(); -const isEditable = computed(() => +const isEditable = computed(() => // 是否可编辑明细行 ['create', 'update'].includes(props.formType), -); // 是否可编辑明细行 +); const isStock = computed(() => props.formType === 'stock'); // 是否为拣货模式 const detailMap = reactive< Record diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue index cabac9479..6c1a39acd 100644 --- a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue @@ -22,9 +22,9 @@ const emit = defineEmits<{ refresh: []; }>(); -const isEditable = computed( - () => ['create', 'stock', 'update'].includes(props.formType), -); // 是否可维护收货明细(编辑或上架态) +const isEditable = computed(() => // 是否可维护收货明细(编辑或上架态) + ['create', 'stock', 'update'].includes(props.formType), +); /** 添加收货明细 */ function handleCreate() { diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/form.vue b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/form.vue index 52678831f..b7159bd52 100644 --- a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/form.vue +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/form.vue @@ -38,23 +38,18 @@ const canSubmit = computed(() => // 是否可提交 formData.value?.status === MesWmOutsourceReceiptStatusEnum.PREPARE, ); const getTitle = computed(() => { - switch (formType.value) { - case 'detail': { - return $t('ui.actionTitle.view', ['外协入库单']); - } - case 'finish': { - return '完成入库'; - } - case 'stock': { - return '执行上架'; - } - case 'update': { - return $t('ui.actionTitle.edit', ['外协入库单']); - } - default: { - return $t('ui.actionTitle.create', ['外协入库单']); - } + if (formType.value === 'detail') { + return $t('ui.actionTitle.view', ['外协入库单']); } + if (formType.value === 'stock') { + return '执行上架'; + } + if (formType.value === 'finish') { + return '完成入库'; + } + return formType.value === 'update' + ? $t('ui.actionTitle.edit', ['外协入库单']) + : $t('ui.actionTitle.create', ['外协入库单']); }); const [Form, formApi] = useVbenForm({ diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-list.vue index 362c06a38..c1411a4b2 100644 --- a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-list.vue +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-list.vue @@ -28,9 +28,9 @@ const props = defineProps<{ receiptId: number; }>(); -const isEditable = computed(() => +const isEditable = computed(() => // 是否可编辑明细行 ['create', 'update'].includes(props.formType), -); // 是否可编辑明细行 +); const isStock = computed(() => props.formType === 'stock'); // 是否为上架模式 const detailMap = reactive< Record