From 990d0a78fb30dcff39d429c473c800fdbe3564a9 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 May 2026 09:04:41 +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?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/mes/wm/outsourceissue/index.vue | 209 +++++++ .../wm/outsourceissue/modules/detail-form.vue | 104 ++++ .../wm/outsourceissue/modules/detail-list.vue | 103 ++++ .../mes/wm/outsourceissue/modules/form.vue | 240 ++++++++ .../wm/outsourceissue/modules/line-form.vue | 97 ++++ .../wm/outsourceissue/modules/line-list.vue | 223 +++++++ .../src/views/mes/wm/outsourcereceipt/data.ts | 542 +++++++++++++++++ .../views/mes/wm/outsourcereceipt/index.vue | 209 +++++++ .../outsourcereceipt/modules/detail-form.vue | 103 ++++ .../outsourcereceipt/modules/detail-list.vue | 123 ++++ .../mes/wm/outsourcereceipt/modules/form.vue | 230 ++++++++ .../wm/outsourcereceipt/modules/line-form.vue | 99 ++++ .../wm/outsourcereceipt/modules/line-list.vue | 233 ++++++++ apps/web-ele/src/api/mes/pro/card/index.ts | 35 ++ apps/web-ele/src/api/mes/pro/task/index.ts | 27 + .../src/api/mes/pro/workorder/index.ts | 84 ++- apps/web-ele/src/views/mes/utils/constants.ts | 6 + .../src/views/mes/wm/outsourceissue/data.ts | 491 ++++++++++++++++ .../src/views/mes/wm/outsourceissue/index.vue | 211 +++++++ .../wm/outsourceissue/modules/detail-form.vue | 104 ++++ .../wm/outsourceissue/modules/detail-list.vue | 103 ++++ .../mes/wm/outsourceissue/modules/form.vue | 247 ++++++++ .../wm/outsourceissue/modules/line-form.vue | 97 ++++ .../wm/outsourceissue/modules/line-list.vue | 223 +++++++ .../src/views/mes/wm/outsourcereceipt/data.ts | 546 ++++++++++++++++++ .../views/mes/wm/outsourcereceipt/index.vue | 211 +++++++ .../outsourcereceipt/modules/detail-form.vue | 104 ++++ .../outsourcereceipt/modules/detail-list.vue | 122 ++++ .../mes/wm/outsourcereceipt/modules/form.vue | 238 ++++++++ .../wm/outsourcereceipt/modules/line-form.vue | 98 ++++ .../wm/outsourcereceipt/modules/line-list.vue | 234 ++++++++ 31 files changed, 5677 insertions(+), 19 deletions(-) create mode 100644 apps/web-antd/src/views/mes/wm/outsourceissue/index.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourceissue/modules/form.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/data.ts create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/index.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/form.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/data.ts create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/index.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/modules/form.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/data.ts create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/index.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/form.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-list.vue diff --git a/apps/web-antd/src/views/mes/wm/outsourceissue/index.vue b/apps/web-antd/src/views/mes/wm/outsourceissue/index.vue new file mode 100644 index 000000000..4e80842d9 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/index.vue @@ -0,0 +1,209 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-form.vue new file mode 100644 index 000000000..16504ff2c --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-list.vue new file mode 100644 index 000000000..69633aa49 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + 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 new file mode 100644 index 000000000..160e932af --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/form.vue @@ -0,0 +1,240 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-form.vue new file mode 100644 index 000000000..b0f8f6da0 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-form.vue @@ -0,0 +1,97 @@ + + + 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 new file mode 100644 index 000000000..30548696d --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourceissue/modules/line-list.vue @@ -0,0 +1,223 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/data.ts b/apps/web-antd/src/views/mes/wm/outsourcereceipt/data.ts new file mode 100644 index 000000000..a4b96f1db --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/data.ts @@ -0,0 +1,542 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder'; +import type { MesWmOutsourceReceiptApi } from '#/api/mes/wm/outsourcereceipt'; +import type { MesWmOutsourceReceiptDetailApi } from '#/api/mes/wm/outsourcereceipt/detail'; +import type { MesWmOutsourceReceiptLineApi } from '#/api/mes/wm/outsourcereceipt/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { Button } from 'ant-design-vue'; + +import { z } from '#/adapter/form'; +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { getRangePickerDefaultProps } from '#/utils'; +import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue'; +import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue'; +import { + MesAutoCodeRuleCode, + MesProWorkOrderStatusEnum, + MesProWorkOrderTypeEnum, +} from '#/views/mes/utils/constants'; +import { + WmWarehouseAreaSelect, + WmWarehouseLocationSelect, + WmWarehouseSelect, +} from '#/views/mes/wm/warehouse/components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'finish' | 'stock' | 'update'; + +/** 表单头部是否只读(上架、详情、完成态) */ +function isHeaderReadonly(formType: FormType): boolean { + return ( + formType === 'detail' || formType === 'finish' || formType === 'stock' + ); +} + +/** 新增/修改的表单 */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'status', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'code', + label: '入库单编号', + component: 'Input', + componentProps: { + placeholder: '请输入入库单编号', + }, + rules: 'required', + suffix: isHeaderReadonly(formType) + ? undefined + : () => + h( + Button, + { + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_OUTSOURCE_RECEIPT_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入入库单名称', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '外协工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + // 选择外协工单后,自动回填供应商 + onChange: async (workOrder?: MesProWorkOrderApi.WorkOrder) => { + await formApi?.setFieldValue('vendorId', workOrder?.vendorId); + }, + status: MesProWorkOrderStatusEnum.CONFIRMED, + type: MesProWorkOrderTypeEnum.OUTSOURCE, + }, + rules: 'selectRequired', + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD', + placeholder: '请选择入库日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '入库单编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入入库单编号', + }, + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入入库单名称', + }, + }, + { + fieldName: 'workOrderCode', + label: '外协工单号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入外协工单号', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions( + DICT_TYPE.MES_WM_OUTSOURCE_RECEIPT_STATUS, + 'number', + ), + placeholder: '请选择单据状态', + }, + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '入库单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '入库单名称', + minWidth: 150, + }, + { + field: 'workOrderCode', + title: '外协工单号', + minWidth: 140, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 120, + }, + { + field: 'receiptDate', + title: '入库日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_OUTSOURCE_RECEIPT_STATUS }, + }, + }, + { + title: '操作', + width: 240, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 入库单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + type: 'expand', + width: 48, + slots: { content: 'detail' }, + }, + { + field: 'itemCode', + title: '物料编码', + minWidth: 120, + }, + { + field: 'itemName', + title: '物料名称', + minWidth: 140, + }, + { + field: 'specification', + title: '规格型号', + minWidth: 120, + }, + { + field: 'unitMeasureName', + title: '单位', + width: 80, + }, + { + field: 'quantity', + title: '入库数量', + width: 100, + }, + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + field: 'iqcCheckFlag', + title: '是否检验', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualityStatus', + title: '质量状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, + }, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 入库单行新增/修改的表单 */ +export function useLineFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '入库数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入入库数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + placeholder: '系统自动生成', + }, + }, + { + fieldName: 'productionDate', + label: '生产日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择生产日期', + valueFormat: 'x', + }, + }, + { + fieldName: 'expireDate', + label: '有效期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择有效期', + valueFormat: 'x', + }, + }, + { + fieldName: 'lotNumber', + label: '批号', + component: 'Input', + componentProps: { + placeholder: '请输入批号', + }, + }, + { + fieldName: 'iqcCheckFlag', + label: '是否质检', + component: 'Switch', + rules: z.boolean().default(false), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 入库明细子表的字段 */ +export function useDetailGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'warehouseName', + title: '仓库名称', + minWidth: 100, + }, + { + field: 'locationName', + title: '库区名称', + minWidth: 100, + }, + { + field: 'areaName', + title: '库位名称', + minWidth: 100, + }, + { + field: 'quantity', + title: '数量', + width: 100, + }, + ...(editable + ? [ + { + title: '操作', + width: 120, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 入库明细新增/修改的表单 */ +export function useDetailFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + rules: 'required', + }, + { + fieldName: 'warehouseId', + label: '入库仓库', + component: markRaw(WmWarehouseSelect), + componentProps: { + // 切换仓库后清空库区和库位 + onChange: async () => { + await formApi?.setValues({ + areaId: undefined, + locationId: undefined, + }); + }, + placeholder: '请选择仓库', + }, + rules: 'selectRequired', + }, + { + fieldName: 'locationId', + label: '库区', + component: markRaw(WmWarehouseLocationSelect), + componentProps: { + placeholder: '请选择库区', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['warehouseId'], + componentProps: (values) => ({ + // 切换库区后清空库位 + onChange: async () => { + await formApi?.setFieldValue('areaId', undefined); + }, + placeholder: '请选择库区', + warehouseId: values.warehouseId, + }), + }, + }, + { + fieldName: 'areaId', + label: '库位', + component: markRaw(WmWarehouseAreaSelect), + componentProps: { + placeholder: '请选择库位', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['locationId'], + componentProps: (values) => ({ + locationId: values.locationId, + placeholder: '请选择库位', + }), + }, + }, + { + fieldName: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/index.vue b/apps/web-antd/src/views/mes/wm/outsourcereceipt/index.vue new file mode 100644 index 000000000..ae1def5f0 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/index.vue @@ -0,0 +1,209 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue new file mode 100644 index 000000000..750185705 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue @@ -0,0 +1,103 @@ + + + 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 new file mode 100644 index 000000000..8fc1718d9 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue @@ -0,0 +1,123 @@ + + + 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 new file mode 100644 index 000000000..76879cb67 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/form.vue @@ -0,0 +1,230 @@ + + + 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 new file mode 100644 index 000000000..e2b9d6541 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-form.vue @@ -0,0 +1,99 @@ + + + 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 new file mode 100644 index 000000000..23e00bf2e --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/outsourcereceipt/modules/line-list.vue @@ -0,0 +1,233 @@ + + + diff --git a/apps/web-ele/src/api/mes/pro/card/index.ts b/apps/web-ele/src/api/mes/pro/card/index.ts index 06c6cb04f..a9d123cc3 100644 --- a/apps/web-ele/src/api/mes/pro/card/index.ts +++ b/apps/web-ele/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-ele/src/api/mes/pro/task/index.ts b/apps/web-ele/src/api/mes/pro/task/index.ts index d7bfd2f5e..5e160c840 100644 --- a/apps/web-ele/src/api/mes/pro/task/index.ts +++ b/apps/web-ele/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-ele/src/api/mes/pro/workorder/index.ts b/apps/web-ele/src/api/mes/pro/workorder/index.ts index 24de7d057..c4c0a152a 100644 --- a/apps/web-ele/src/api/mes/pro/workorder/index.ts +++ b/apps/web-ele/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-ele/src/views/mes/utils/constants.ts b/apps/web-ele/src/views/mes/utils/constants.ts index 19315fc41..08b97af14 100644 --- a/apps/web-ele/src/views/mes/utils/constants.ts +++ b/apps/web-ele/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-ele/src/views/mes/wm/outsourceissue/data.ts b/apps/web-ele/src/views/mes/wm/outsourceissue/data.ts new file mode 100644 index 000000000..67abe167e --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/data.ts @@ -0,0 +1,491 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmOutsourceIssueApi } from '#/api/mes/wm/outsourceissue'; +import type { MesWmOutsourceIssueDetailApi } from '#/api/mes/wm/outsourceissue/detail'; +import type { MesWmOutsourceIssueLineApi } from '#/api/mes/wm/outsourceissue/line'; + +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 { getRangePickerDefaultProps } from '#/utils'; +import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue'; +import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue'; +import { + MesAutoCodeRuleCode, + MesProWorkOrderStatusEnum, + MesProWorkOrderTypeEnum, +} from '#/views/mes/utils/constants'; +import { WmMaterialStockSelect } from '#/views/mes/wm/materialstock/components'; +import { + WmWarehouseAreaSelect, + WmWarehouseLocationSelect, + WmWarehouseSelect, +} from '#/views/mes/wm/warehouse/components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'finish' | 'stock' | 'update'; + +/** 表单头部是否只读(拣货、详情、领出态) */ +function isHeaderReadonly(formType: FormType): boolean { + return ( + formType === 'detail' || formType === 'finish' || formType === 'stock' + ); +} + +/** 新增/修改的表单 */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'status', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'code', + label: '发料单编号', + component: 'Input', + componentProps: { + placeholder: '请输入发料单编号', + }, + rules: 'required', + suffix: isHeaderReadonly(formType) + ? undefined + : () => + h( + ElButton, + { + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_OUTSOURCE_ISSUE_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '发料单名称', + component: 'Input', + componentProps: { + placeholder: '请输入发料单名称', + }, + rules: 'required', + }, + { + fieldName: 'issueDate', + label: '发料日期', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD', + placeholder: '请选择发料日期', + type: 'date', + valueFormat: 'x', + }, + }, + { + fieldName: 'workOrderId', + label: '外协工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + // 选择外协工单后,自动回填供应商 + onChange: async (workOrder?: MesProWorkOrderApi.WorkOrder) => { + await formApi?.setFieldValue('vendorId', workOrder?.vendorId); + }, + status: MesProWorkOrderStatusEnum.CONFIRMED, + type: MesProWorkOrderTypeEnum.OUTSOURCE, + }, + rules: 'selectRequired', + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '发料单编号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入发料单编号', + }, + }, + { + fieldName: 'name', + label: '发料单名称', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入发料单名称', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + { + fieldName: 'issueDate', + label: '发料日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '发料单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '发料单名称', + minWidth: 150, + }, + { + field: 'workOrderCode', + title: '生产工单号', + minWidth: 140, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 120, + }, + { + field: 'issueDate', + title: '发料日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_OUTSOURCE_ISSUE_STATUS }, + }, + }, + { + title: '操作', + width: 240, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 发料单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + type: 'expand', + width: 48, + slots: { content: 'detail' }, + }, + { + field: 'itemCode', + title: '物料编码', + minWidth: 120, + }, + { + field: 'itemName', + title: '物料名称', + minWidth: 140, + }, + { + field: 'specification', + title: '规格型号', + minWidth: 120, + }, + { + field: 'unitMeasureName', + title: '单位', + width: 80, + }, + { + field: 'quantity', + title: '领料数量', + width: 100, + }, + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + field: 'remark', + title: '备注', + minWidth: 150, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 发料单行新增/修改的表单 */ +export function useLineFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '发料数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入发料数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 发料明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'warehouseName', + title: '仓库名称', + minWidth: 100, + }, + { + field: 'locationName', + title: '库区名称', + minWidth: 100, + }, + { + field: 'areaName', + title: '库位名称', + minWidth: 100, + }, + { + field: 'quantity', + title: '数量', + width: 100, + }, + ...(stockable + ? [ + { + title: '操作', + width: 120, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 发料明细新增/修改的表单 */ +export function useDetailFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'quantityMax', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'materialStockId', + label: '库存记录', + component: markRaw(WmMaterialStockSelect), + componentProps: { + // 选择库存记录后,自动回填仓库/库区/库位/批次/数量 + onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => { + await formApi?.setValues({ + areaId: stock?.areaId, + batchCode: stock?.batchCode, + batchId: stock?.batchId, + locationId: stock?.locationId, + quantity: stock?.quantity, + quantityMax: stock?.quantity, + warehouseId: stock?.warehouseId, + }); + }, + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + itemId: values.itemId, + }), + }, + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + dependencies: { + triggerFields: ['quantityMax'], + componentProps: (values) => ({ + class: '!w-full', + controlsPosition: 'right', + max: values.quantityMax, + min: 0, + placeholder: '请输入数量', + precision: 2, + }), + }, + }, + { + fieldName: 'warehouseId', + label: '发料仓库', + component: markRaw(WmWarehouseSelect), + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'locationId', + label: '库区', + component: markRaw(WmWarehouseLocationSelect), + componentProps: { + disabled: true, + }, + dependencies: { + triggerFields: ['warehouseId'], + componentProps: (values) => ({ + disabled: true, + warehouseId: values.warehouseId, + }), + }, + }, + { + fieldName: 'areaId', + label: '库位', + component: markRaw(WmWarehouseAreaSelect), + componentProps: { + disabled: true, + }, + dependencies: { + triggerFields: ['locationId'], + componentProps: (values) => ({ + disabled: true, + locationId: values.locationId, + }), + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/wm/outsourceissue/index.vue b/apps/web-ele/src/views/mes/wm/outsourceissue/index.vue new file mode 100644 index 000000000..c241d9808 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/index.vue @@ -0,0 +1,211 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-form.vue new file mode 100644 index 000000000..803fb3c7a --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-list.vue new file mode 100644 index 000000000..f574b338f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + 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 new file mode 100644 index 000000000..708935fa0 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/form.vue @@ -0,0 +1,247 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-form.vue new file mode 100644 index 000000000..d692a5883 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-form.vue @@ -0,0 +1,97 @@ + + + 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 new file mode 100644 index 000000000..a8ba2b4f3 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourceissue/modules/line-list.vue @@ -0,0 +1,223 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/data.ts b/apps/web-ele/src/views/mes/wm/outsourcereceipt/data.ts new file mode 100644 index 000000000..c908feff8 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/data.ts @@ -0,0 +1,546 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesProWorkOrderApi } from '#/api/mes/pro/workorder'; +import type { MesWmOutsourceReceiptApi } from '#/api/mes/wm/outsourcereceipt'; +import type { MesWmOutsourceReceiptDetailApi } from '#/api/mes/wm/outsourcereceipt/detail'; +import type { MesWmOutsourceReceiptLineApi } from '#/api/mes/wm/outsourcereceipt/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { ElButton } from 'element-plus'; + +import { z } from '#/adapter/form'; +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +import { getRangePickerDefaultProps } from '#/utils'; +import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue'; +import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue'; +import { + MesAutoCodeRuleCode, + MesProWorkOrderStatusEnum, + MesProWorkOrderTypeEnum, +} from '#/views/mes/utils/constants'; +import { + WmWarehouseAreaSelect, + WmWarehouseLocationSelect, + WmWarehouseSelect, +} from '#/views/mes/wm/warehouse/components'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'finish' | 'stock' | 'update'; + +/** 表单头部是否只读(上架、详情、完成态) */ +function isHeaderReadonly(formType: FormType): boolean { + return ( + formType === 'detail' || formType === 'finish' || formType === 'stock' + ); +} + +/** 新增/修改的表单 */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'id', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'status', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'code', + label: '入库单编号', + component: 'Input', + componentProps: { + placeholder: '请输入入库单编号', + }, + rules: 'required', + suffix: isHeaderReadonly(formType) + ? undefined + : () => + h( + ElButton, + { + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_OUTSOURCE_RECEIPT_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入入库单名称', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '外协工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + // 选择外协工单后,自动回填供应商 + onChange: async (workOrder?: MesProWorkOrderApi.WorkOrder) => { + await formApi?.setFieldValue('vendorId', workOrder?.vendorId); + }, + status: MesProWorkOrderStatusEnum.CONFIRMED, + type: MesProWorkOrderTypeEnum.OUTSOURCE, + }, + rules: 'selectRequired', + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'DatePicker', + componentProps: { + format: 'YYYY-MM-DD', + placeholder: '请选择入库日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 列表的搜索表单 */ +export function useGridFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'code', + label: '入库单编号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入入库单编号', + }, + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入入库单名称', + }, + }, + { + fieldName: 'workOrderCode', + label: '外协工单号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入外协工单号', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + { + fieldName: 'status', + label: '状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions( + DICT_TYPE.MES_WM_OUTSOURCE_RECEIPT_STATUS, + 'number', + ), + placeholder: '请选择单据状态', + }, + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '入库单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '入库单名称', + minWidth: 150, + }, + { + field: 'workOrderCode', + title: '外协工单号', + minWidth: 140, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 120, + }, + { + field: 'receiptDate', + title: '入库日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_OUTSOURCE_RECEIPT_STATUS }, + }, + }, + { + title: '操作', + width: 240, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 入库单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + type: 'expand', + width: 48, + slots: { content: 'detail' }, + }, + { + field: 'itemCode', + title: '物料编码', + minWidth: 120, + }, + { + field: 'itemName', + title: '物料名称', + minWidth: 140, + }, + { + field: 'specification', + title: '规格型号', + minWidth: 120, + }, + { + field: 'unitMeasureName', + title: '单位', + width: 80, + }, + { + field: 'quantity', + title: '入库数量', + width: 100, + }, + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + field: 'iqcCheckFlag', + title: '是否检验', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualityStatus', + title: '质量状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, + }, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 入库单行新增/修改的表单 */ +export function useLineFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + }, + { + fieldName: 'quantity', + label: '入库数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入入库数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + placeholder: '系统自动生成', + }, + }, + { + fieldName: 'productionDate', + label: '生产日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择生产日期', + type: 'date', + valueFormat: 'x', + }, + }, + { + fieldName: 'expireDate', + label: '有效期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择有效期', + type: 'date', + valueFormat: 'x', + }, + }, + { + fieldName: 'lotNumber', + label: '批号', + component: 'Input', + componentProps: { + placeholder: '请输入批号', + }, + }, + { + fieldName: 'iqcCheckFlag', + label: '是否质检', + component: 'Switch', + rules: z.boolean().default(false), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 入库明细子表的字段 */ +export function useDetailGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'warehouseName', + title: '仓库名称', + minWidth: 100, + }, + { + field: 'locationName', + title: '库区名称', + minWidth: 100, + }, + { + field: 'areaName', + title: '库位名称', + minWidth: 100, + }, + { + field: 'quantity', + title: '数量', + width: 100, + }, + ...(editable + ? [ + { + title: '操作', + width: 120, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 入库明细新增/修改的表单 */ +export function useDetailFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + rules: 'required', + }, + { + fieldName: 'warehouseId', + label: '入库仓库', + component: markRaw(WmWarehouseSelect), + componentProps: { + // 切换仓库后清空库区和库位 + onChange: async () => { + await formApi?.setValues({ + areaId: undefined, + locationId: undefined, + }); + }, + placeholder: '请选择仓库', + }, + rules: 'selectRequired', + }, + { + fieldName: 'locationId', + label: '库区', + component: markRaw(WmWarehouseLocationSelect), + componentProps: { + placeholder: '请选择库区', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['warehouseId'], + componentProps: (values) => ({ + // 切换库区后清空库位 + onChange: async () => { + await formApi?.setFieldValue('areaId', undefined); + }, + placeholder: '请选择库区', + warehouseId: values.warehouseId, + }), + }, + }, + { + fieldName: 'areaId', + label: '库位', + component: markRaw(WmWarehouseAreaSelect), + componentProps: { + placeholder: '请选择库位', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['locationId'], + componentProps: (values) => ({ + locationId: values.locationId, + placeholder: '请选择库位', + }), + }, + }, + { + fieldName: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-2', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/index.vue b/apps/web-ele/src/views/mes/wm/outsourcereceipt/index.vue new file mode 100644 index 000000000..ce3808463 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/index.vue @@ -0,0 +1,211 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue new file mode 100644 index 000000000..c0b3b3572 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + 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 new file mode 100644 index 000000000..cabac9479 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/detail-list.vue @@ -0,0 +1,122 @@ + + + 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 new file mode 100644 index 000000000..52678831f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/form.vue @@ -0,0 +1,238 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-form.vue new file mode 100644 index 000000000..a080867d2 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-form.vue @@ -0,0 +1,98 @@ + + + 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 new file mode 100644 index 000000000..362c06a38 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/outsourcereceipt/modules/line-list.vue @@ -0,0 +1,234 @@ + + +