From 2fd44246f84e244e2e759eba33565ad0a3effe11 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 30 May 2026 10:58:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(mes):=20=E8=BF=81=E7=A7=BB=20wm=20?= =?UTF-8?q?=E9=87=8C=E7=9A=84=20return-*=20=E7=B3=BB=E5=88=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/mes/wm/returnissue/data.ts | 568 +++++++++++++++++ .../src/views/mes/wm/returnissue/index.vue | 221 +++++++ .../wm/returnissue/modules/detail-form.vue | 104 ++++ .../wm/returnissue/modules/detail-list.vue | 103 ++++ .../views/mes/wm/returnissue/modules/form.vue | 225 +++++++ .../mes/wm/returnissue/modules/line-form.vue | 95 +++ .../mes/wm/returnissue/modules/line-list.vue | 247 ++++++++ .../src/views/mes/wm/returnsales/data.ts | 519 ++++++++++++++++ .../src/views/mes/wm/returnsales/index.vue | 221 +++++++ .../wm/returnsales/modules/detail-form.vue | 104 ++++ .../wm/returnsales/modules/detail-list.vue | 103 ++++ .../views/mes/wm/returnsales/modules/form.vue | 233 +++++++ .../mes/wm/returnsales/modules/line-form.vue | 102 ++++ .../mes/wm/returnsales/modules/line-list.vue | 244 ++++++++ .../src/views/mes/wm/returnvendor/data.ts | 533 ++++++++++++++++ .../src/views/mes/wm/returnvendor/index.vue | 209 +++++++ .../wm/returnvendor/modules/detail-form.vue | 104 ++++ .../wm/returnvendor/modules/detail-list.vue | 103 ++++ .../mes/wm/returnvendor/modules/form.vue | 238 ++++++++ .../mes/wm/returnvendor/modules/line-form.vue | 99 +++ .../mes/wm/returnvendor/modules/line-list.vue | 234 +++++++ .../src/views/mes/wm/returnissue/data.ts | 571 ++++++++++++++++++ .../src/views/mes/wm/returnissue/index.vue | 224 +++++++ .../wm/returnissue/modules/detail-form.vue | 104 ++++ .../wm/returnissue/modules/detail-list.vue | 103 ++++ .../views/mes/wm/returnissue/modules/form.vue | 230 +++++++ .../mes/wm/returnissue/modules/line-form.vue | 95 +++ .../mes/wm/returnissue/modules/line-list.vue | 249 ++++++++ .../src/views/mes/wm/returnsales/data.ts | 521 ++++++++++++++++ .../src/views/mes/wm/returnsales/index.vue | 224 +++++++ .../wm/returnsales/modules/detail-form.vue | 104 ++++ .../wm/returnsales/modules/detail-list.vue | 103 ++++ .../views/mes/wm/returnsales/modules/form.vue | 242 ++++++++ .../mes/wm/returnsales/modules/line-form.vue | 102 ++++ .../mes/wm/returnsales/modules/line-list.vue | 245 ++++++++ .../src/views/mes/wm/returnvendor/data.ts | 535 ++++++++++++++++ .../src/views/mes/wm/returnvendor/index.vue | 211 +++++++ .../wm/returnvendor/modules/detail-form.vue | 104 ++++ .../wm/returnvendor/modules/detail-list.vue | 103 ++++ .../mes/wm/returnvendor/modules/form.vue | 244 ++++++++ .../mes/wm/returnvendor/modules/line-form.vue | 99 +++ .../mes/wm/returnvendor/modules/line-list.vue | 235 +++++++ 42 files changed, 9257 insertions(+) create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/data.ts create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/index.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/modules/detail-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/modules/detail-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/modules/form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/modules/line-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnissue/modules/line-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/data.ts create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/index.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/modules/detail-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/modules/detail-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/modules/form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/modules/line-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnsales/modules/line-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/data.ts create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/index.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-list.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/modules/form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/modules/line-form.vue create mode 100644 apps/web-antd/src/views/mes/wm/returnvendor/modules/line-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/data.ts create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/index.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/modules/detail-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/modules/detail-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/modules/form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/modules/line-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnissue/modules/line-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/data.ts create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/index.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/modules/detail-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/modules/detail-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/modules/form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/modules/line-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnsales/modules/line-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/data.ts create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/index.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-list.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/modules/form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/modules/line-form.vue create mode 100644 apps/web-ele/src/views/mes/wm/returnvendor/modules/line-list.vue diff --git a/apps/web-antd/src/views/mes/wm/returnissue/data.ts b/apps/web-antd/src/views/mes/wm/returnissue/data.ts new file mode 100644 index 000000000..f1320acca --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/data.ts @@ -0,0 +1,568 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmReturnIssueApi } from '#/api/mes/wm/returnissue'; +import type { MesWmReturnIssueDetailApi } from '#/api/mes/wm/returnissue/detail'; +import type { MesWmReturnIssueLineApi } from '#/api/mes/wm/returnissue/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 MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import MdWorkstationSelect from '#/views/mes/md/workstation/components/md-workstation-select.vue'; +import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue'; +import { + MesAutoCodeRuleCode, + MesProWorkOrderStatusEnum, +} 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( + Button, + { + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_RETURN_ISSUE_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '退料单名称', + component: 'Input', + componentProps: { + placeholder: '请输入退料单名称', + }, + rules: 'required', + }, + { + fieldName: 'type', + label: '退料类型', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_WM_RETURN_ISSUE_TYPE, 'number'), + placeholder: '请选择退料类型', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + rules: 'selectRequired', + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'returnDate', + label: '退料日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择退料日期', + showTime: true, + valueFormat: 'x', + }, + }, + { + 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: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + placeholder: '请选择生产工单', + }, + }, + { + fieldName: 'type', + label: '退料类型', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_WM_RETURN_ISSUE_TYPE, 'number'), + placeholder: '请选择退料类型', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '退料单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '退料单名称', + minWidth: 150, + }, + { + field: 'type', + title: '退料类型', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_ISSUE_TYPE }, + }, + }, + { + field: 'workOrderCode', + title: '生产工单', + minWidth: 140, + }, + { + field: 'workstationName', + title: '工作站', + minWidth: 120, + }, + { + field: 'returnDate', + title: '退料日期', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_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: 'rqcCheckFlag', + title: '是否检测', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualityStatus', + title: '质量状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, + }, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 退料单行新增/修改的表单 */ +export function useLineFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'materialStockId', + label: '库存记录', + component: markRaw(WmMaterialStockSelect), + componentProps: { + // 选择库存记录后,自动回填物料/批次/数量 + onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => { + await formApi?.setValues({ + batchCode: stock?.batchCode, + batchId: stock?.batchId, + itemId: stock?.itemId, + quantity: stock?.quantity, + quantityMax: stock?.quantity, + }); + }, + virtualFilter: 'only', + }, + rules: 'selectRequired', + }, + { + fieldName: 'quantityMax', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'quantity', + label: '退料数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入退料数量', + precision: 2, + }, + rules: 'required', + dependencies: { + triggerFields: ['quantityMax'], + componentProps: (values) => ({ + class: '!w-full', + max: values.quantityMax, + min: 0, + placeholder: '请输入退料数量', + precision: 2, + }), + }, + }, + { + fieldName: 'rqcCheckFlag', + label: '需要质检', + component: 'Switch', + rules: z.boolean().default(false), + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + placeholder: '选择库存后自动带出', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 上架明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + 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: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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, + }); + }, + virtualFilter: 'only', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + itemId: values.itemId, + virtualFilter: 'only', + }), + }, + }, + { + fieldName: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + dependencies: { + triggerFields: ['quantityMax'], + componentProps: (values) => ({ + class: '!w-full', + 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-antd/src/views/mes/wm/returnissue/index.vue b/apps/web-antd/src/views/mes/wm/returnissue/index.vue new file mode 100644 index 000000000..4f8aeddfb --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/index.vue @@ -0,0 +1,221 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnissue/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/returnissue/modules/detail-form.vue new file mode 100644 index 000000000..032c77135 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnissue/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/returnissue/modules/detail-list.vue new file mode 100644 index 000000000..6f4458f9e --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnissue/modules/form.vue b/apps/web-antd/src/views/mes/wm/returnissue/modules/form.vue new file mode 100644 index 000000000..b971108b1 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/modules/form.vue @@ -0,0 +1,225 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnissue/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/returnissue/modules/line-form.vue new file mode 100644 index 000000000..7cdc60151 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/modules/line-form.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnissue/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/returnissue/modules/line-list.vue new file mode 100644 index 000000000..216dbd665 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnissue/modules/line-list.vue @@ -0,0 +1,247 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnsales/data.ts b/apps/web-antd/src/views/mes/wm/returnsales/data.ts new file mode 100644 index 000000000..b540e86bf --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/data.ts @@ -0,0 +1,519 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmReturnSalesApi } from '#/api/mes/wm/returnsales'; +import type { MesWmReturnSalesDetailApi } from '#/api/mes/wm/returnsales/detail'; +import type { MesWmReturnSalesLineApi } from '#/api/mes/wm/returnsales/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 MdClientSelect from '#/views/mes/md/client/components/md-client-select.vue'; +import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; +import { WmBatchSelect } from '#/views/mes/wm/batch/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( + Button, + { + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_RETURN_SALES_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '退货单名称', + component: 'Input', + componentProps: { + placeholder: '请输入退货单名称', + }, + rules: 'required', + }, + { + fieldName: 'salesOrderCode', + label: '销售订单号', + component: 'Input', + componentProps: { + placeholder: '请输入销售订单号', + }, + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + placeholder: '请选择客户', + }, + rules: 'selectRequired', + }, + { + fieldName: 'returnDate', + label: '退货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择退货日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'returnReason', + label: '退货原因', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入退货原因', + rows: 2, + }, + 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: 'salesOrderCode', + label: '销售订单号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入销售订单号', + }, + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + placeholder: '请选择客户', + }, + }, + { + fieldName: 'status', + label: '单据状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_WM_RETURN_SALES_STATUS, 'number'), + placeholder: '请选择单据状态', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '退货单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '退货单名称', + minWidth: 150, + }, + { + field: 'salesOrderCode', + title: '销售订单号', + minWidth: 140, + }, + { + field: 'clientCode', + title: '客户编码', + minWidth: 120, + }, + { + field: 'clientName', + title: '客户名称', + minWidth: 150, + }, + { + field: 'returnReason', + title: '退货原因', + minWidth: 150, + }, + { + field: 'returnDate', + title: '退货日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_SALES_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: 'rqcCheckFlag', + title: '是否需要质检', + width: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualityStatus', + title: '质量状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, + }, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 退货单行新增/修改的表单 */ +export function useLineFormSchema( + clientId?: number, + salesOrderCode?: string, +): 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: 'batchId', + label: '批次', + component: markRaw(WmBatchSelect), + componentProps: { + clientId, + placeholder: '请选择批次', + salesOrderCode, + }, + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + clientId, + itemId: values.itemId, + placeholder: '请选择批次', + salesOrderCode, + }), + }, + }, + { + fieldName: 'rqcCheckFlag', + label: '需要质检', + component: 'Switch', + rules: z.boolean().default(true), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 上架明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + 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: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + rules: 'required', + }, + { + fieldName: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/wm/returnsales/index.vue b/apps/web-antd/src/views/mes/wm/returnsales/index.vue new file mode 100644 index 000000000..e746b54b8 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/index.vue @@ -0,0 +1,221 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnsales/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/returnsales/modules/detail-form.vue new file mode 100644 index 000000000..7fe34f713 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnsales/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/returnsales/modules/detail-list.vue new file mode 100644 index 000000000..fa0355430 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnsales/modules/form.vue b/apps/web-antd/src/views/mes/wm/returnsales/modules/form.vue new file mode 100644 index 000000000..18f98fb6b --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/modules/form.vue @@ -0,0 +1,233 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnsales/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/returnsales/modules/line-form.vue new file mode 100644 index 000000000..0736b8bb3 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/modules/line-form.vue @@ -0,0 +1,102 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnsales/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/returnsales/modules/line-list.vue new file mode 100644 index 000000000..316bbe8da --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnsales/modules/line-list.vue @@ -0,0 +1,244 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnvendor/data.ts b/apps/web-antd/src/views/mes/wm/returnvendor/data.ts new file mode 100644 index 000000000..0b4d33526 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/data.ts @@ -0,0 +1,533 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmReturnVendorApi } from '#/api/mes/wm/returnvendor'; +import type { MesWmReturnVendorDetailApi } from '#/api/mes/wm/returnvendor/detail'; +import type { MesWmReturnVendorLineApi } from '#/api/mes/wm/returnvendor/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +import { Button } from 'ant-design-vue'; + +import { generateAutoCode } from '#/api/mes/md/autocode/record'; +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 { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; +import { WmBatchSelect } from '#/views/mes/wm/batch/components'; +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( + Button, + { + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_RETURN_VENDOR_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '退货单名称', + component: 'Input', + componentProps: { + placeholder: '请输入退货单名称', + }, + rules: 'required', + }, + { + fieldName: 'purchaseOrderCode', + label: '采购订单号', + component: 'Input', + componentProps: { + placeholder: '请输入采购订单号', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + rules: 'selectRequired', + }, + { + fieldName: 'returnDate', + label: '退货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择退货日期', + showTime: true, + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'returnReason', + label: '退货原因', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入退货原因', + rows: 2, + }, + }, + { + fieldName: 'transportCode', + label: '运单号', + component: 'Input', + componentProps: { + placeholder: '请输入运单号', + }, + }, + { + fieldName: 'transportTelephone', + label: '联系电话', + component: 'Input', + 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: { + allowClear: true, + placeholder: '请输入退货单编号', + }, + }, + { + fieldName: 'name', + label: '退货单名称', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入退货单名称', + }, + }, + { + fieldName: 'purchaseOrderCode', + label: '采购订单编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入采购订单编号', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '退货单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '退货单名称', + minWidth: 150, + }, + { + field: 'purchaseOrderCode', + title: '采购订单号', + minWidth: 140, + }, + { + field: 'vendorCode', + title: '供应商编码', + minWidth: 120, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 150, + }, + { + field: 'returnDate', + title: '退货日期', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_VENDOR_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, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 退货单行新增/修改的表单 */ +export function useLineFormSchema( + vendorId?: number, + formApi?: VbenFormApi, +): 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: 'batchId', + label: '批次号', + component: markRaw(WmBatchSelect), + componentProps: { + // 选择批次后同步批次号 + onChange: async (batch?: { code?: string }) => { + await formApi?.setFieldValue('batchCode', batch?.code); + }, + vendorId, + }, + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + itemId: values.itemId, + vendorId, + }), + }, + }, + { + fieldName: 'batchCode', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 拣货明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + 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: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + dependencies: { + triggerFields: ['quantityMax'], + componentProps: (values) => ({ + class: '!w-full', + 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-antd/src/views/mes/wm/returnvendor/index.vue b/apps/web-antd/src/views/mes/wm/returnvendor/index.vue new file mode 100644 index 000000000..eaa32e016 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/index.vue @@ -0,0 +1,209 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-form.vue new file mode 100644 index 000000000..f4a27886b --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-list.vue new file mode 100644 index 000000000..4f91e3148 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnvendor/modules/form.vue b/apps/web-antd/src/views/mes/wm/returnvendor/modules/form.vue new file mode 100644 index 000000000..137cab234 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/modules/form.vue @@ -0,0 +1,238 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnvendor/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/returnvendor/modules/line-form.vue new file mode 100644 index 000000000..a7bf7a6b7 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/modules/line-form.vue @@ -0,0 +1,99 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/returnvendor/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/returnvendor/modules/line-list.vue new file mode 100644 index 000000000..987144edb --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/returnvendor/modules/line-list.vue @@ -0,0 +1,234 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnissue/data.ts b/apps/web-ele/src/views/mes/wm/returnissue/data.ts new file mode 100644 index 000000000..1c7af56c6 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/data.ts @@ -0,0 +1,571 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmReturnIssueApi } from '#/api/mes/wm/returnissue'; +import type { MesWmReturnIssueDetailApi } from '#/api/mes/wm/returnissue/detail'; +import type { MesWmReturnIssueLineApi } from '#/api/mes/wm/returnissue/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 MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import MdWorkstationSelect from '#/views/mes/md/workstation/components/md-workstation-select.vue'; +import ProWorkOrderSelect from '#/views/mes/pro/workorder/components/pro-work-order-select.vue'; +import { + MesAutoCodeRuleCode, + MesProWorkOrderStatusEnum, +} 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_RETURN_ISSUE_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '退料单名称', + component: 'Input', + componentProps: { + placeholder: '请输入退料单名称', + }, + rules: 'required', + }, + { + fieldName: 'type', + label: '退料类型', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_WM_RETURN_ISSUE_TYPE, 'number'), + placeholder: '请选择退料类型', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + rules: 'selectRequired', + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + componentProps: { + placeholder: '请选择工作站', + }, + }, + { + fieldName: 'returnDate', + label: '退料日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择退料日期', + type: 'datetime', + valueFormat: 'x', + }, + }, + { + 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: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + placeholder: '请选择生产工单', + }, + }, + { + fieldName: 'type', + label: '退料类型', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_WM_RETURN_ISSUE_TYPE, 'number'), + placeholder: '请选择退料类型', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '退料单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '退料单名称', + minWidth: 150, + }, + { + field: 'type', + title: '退料类型', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_ISSUE_TYPE }, + }, + }, + { + field: 'workOrderCode', + title: '生产工单', + minWidth: 140, + }, + { + field: 'workstationName', + title: '工作站', + minWidth: 120, + }, + { + field: 'returnDate', + title: '退料日期', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_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: 'rqcCheckFlag', + title: '是否检测', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualityStatus', + title: '质量状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, + }, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 退料单行新增/修改的表单 */ +export function useLineFormSchema(formApi?: VbenFormApi): VbenFormSchema[] { + return [ + { + fieldName: 'materialStockId', + label: '库存记录', + component: markRaw(WmMaterialStockSelect), + componentProps: { + // 选择库存记录后,自动回填物料/批次/数量 + onChange: async (stock?: MesWmMaterialStockApi.MaterialStock) => { + await formApi?.setValues({ + batchCode: stock?.batchCode, + batchId: stock?.batchId, + itemId: stock?.itemId, + quantity: stock?.quantity, + quantityMax: stock?.quantity, + }); + }, + virtualFilter: 'only', + }, + rules: 'selectRequired', + }, + { + fieldName: 'quantityMax', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + 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: 'rqcCheckFlag', + label: '需要质检', + component: 'Switch', + rules: z.boolean().default(false), + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + placeholder: '选择库存后自动带出', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 上架明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + 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: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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, + }); + }, + virtualFilter: 'only', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + itemId: values.itemId, + virtualFilter: 'only', + }), + }, + }, + { + 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/returnissue/index.vue b/apps/web-ele/src/views/mes/wm/returnissue/index.vue new file mode 100644 index 000000000..337029bab --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/index.vue @@ -0,0 +1,224 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnissue/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/returnissue/modules/detail-form.vue new file mode 100644 index 000000000..23586d2a6 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnissue/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/returnissue/modules/detail-list.vue new file mode 100644 index 000000000..de6b28af5 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnissue/modules/form.vue b/apps/web-ele/src/views/mes/wm/returnissue/modules/form.vue new file mode 100644 index 000000000..2cd07a421 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/modules/form.vue @@ -0,0 +1,230 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnissue/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/returnissue/modules/line-form.vue new file mode 100644 index 000000000..30e9da496 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/modules/line-form.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnissue/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/returnissue/modules/line-list.vue new file mode 100644 index 000000000..b1f9374e1 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnissue/modules/line-list.vue @@ -0,0 +1,249 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnsales/data.ts b/apps/web-ele/src/views/mes/wm/returnsales/data.ts new file mode 100644 index 000000000..8924217cf --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/data.ts @@ -0,0 +1,521 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmReturnSalesApi } from '#/api/mes/wm/returnsales'; +import type { MesWmReturnSalesDetailApi } from '#/api/mes/wm/returnsales/detail'; +import type { MesWmReturnSalesLineApi } from '#/api/mes/wm/returnsales/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 MdClientSelect from '#/views/mes/md/client/components/md-client-select.vue'; +import MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; +import { WmBatchSelect } from '#/views/mes/wm/batch/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_RETURN_SALES_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '退货单名称', + component: 'Input', + componentProps: { + placeholder: '请输入退货单名称', + }, + rules: 'required', + }, + { + fieldName: 'salesOrderCode', + label: '销售订单号', + component: 'Input', + componentProps: { + placeholder: '请输入销售订单号', + }, + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + placeholder: '请选择客户', + }, + rules: 'selectRequired', + }, + { + fieldName: 'returnDate', + label: '退货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择退货日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'returnReason', + label: '退货原因', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入退货原因', + rows: 2, + }, + 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: 'salesOrderCode', + label: '销售订单号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入销售订单号', + }, + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + placeholder: '请选择客户', + }, + }, + { + fieldName: 'status', + label: '单据状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_WM_RETURN_SALES_STATUS, 'number'), + placeholder: '请选择单据状态', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '退货单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '退货单名称', + minWidth: 150, + }, + { + field: 'salesOrderCode', + title: '销售订单号', + minWidth: 140, + }, + { + field: 'clientCode', + title: '客户编码', + minWidth: 120, + }, + { + field: 'clientName', + title: '客户名称', + minWidth: 150, + }, + { + field: 'returnReason', + title: '退货原因', + minWidth: 150, + }, + { + field: 'returnDate', + title: '退货日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_SALES_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: 'rqcCheckFlag', + title: '是否需要质检', + width: 120, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualityStatus', + title: '质量状态', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_QUALITY_STATUS }, + }, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 退货单行新增/修改的表单 */ +export function useLineFormSchema( + clientId?: number, + salesOrderCode?: string, +): 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: 'batchId', + label: '批次', + component: markRaw(WmBatchSelect), + componentProps: { + clientId, + placeholder: '请选择批次', + salesOrderCode, + }, + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + clientId, + itemId: values.itemId, + placeholder: '请选择批次', + salesOrderCode, + }), + }, + }, + { + fieldName: 'rqcCheckFlag', + label: '需要质检', + component: 'Switch', + rules: z.boolean().default(true), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 上架明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + 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: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + rules: 'required', + }, + { + fieldName: 'quantity', + label: '数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入数量', + precision: 2, + }, + rules: 'required', + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/wm/returnsales/index.vue b/apps/web-ele/src/views/mes/wm/returnsales/index.vue new file mode 100644 index 000000000..7f36786c4 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/index.vue @@ -0,0 +1,224 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnsales/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/returnsales/modules/detail-form.vue new file mode 100644 index 000000000..8e30d2393 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnsales/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/returnsales/modules/detail-list.vue new file mode 100644 index 000000000..23f1f9817 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnsales/modules/form.vue b/apps/web-ele/src/views/mes/wm/returnsales/modules/form.vue new file mode 100644 index 000000000..8b4094bbe --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/modules/form.vue @@ -0,0 +1,242 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnsales/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/returnsales/modules/line-form.vue new file mode 100644 index 000000000..8566136a8 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/modules/line-form.vue @@ -0,0 +1,102 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnsales/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/returnsales/modules/line-list.vue new file mode 100644 index 000000000..b6f0a66b9 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnsales/modules/line-list.vue @@ -0,0 +1,245 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnvendor/data.ts b/apps/web-ele/src/views/mes/wm/returnvendor/data.ts new file mode 100644 index 000000000..2c551bc2e --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/data.ts @@ -0,0 +1,535 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmReturnVendorApi } from '#/api/mes/wm/returnvendor'; +import type { MesWmReturnVendorDetailApi } from '#/api/mes/wm/returnvendor/detail'; +import type { MesWmReturnVendorLineApi } from '#/api/mes/wm/returnvendor/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 MdItemSelect from '#/views/mes/md/item/components/md-item-select.vue'; +import MdVendorSelect from '#/views/mes/md/vendor/components/md-vendor-select.vue'; +import { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; +import { WmBatchSelect } from '#/views/mes/wm/batch/components'; +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_RETURN_VENDOR_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '退货单名称', + component: 'Input', + componentProps: { + placeholder: '请输入退货单名称', + }, + rules: 'required', + }, + { + fieldName: 'purchaseOrderCode', + label: '采购订单号', + component: 'Input', + componentProps: { + placeholder: '请输入采购订单号', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + rules: 'selectRequired', + }, + { + fieldName: 'returnDate', + label: '退货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择退货日期', + type: 'datetime', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'returnReason', + label: '退货原因', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入退货原因', + rows: 2, + }, + }, + { + fieldName: 'transportCode', + label: '运单号', + component: 'Input', + componentProps: { + placeholder: '请输入运单号', + }, + }, + { + fieldName: 'transportTelephone', + label: '联系电话', + component: 'Input', + 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: 'purchaseOrderCode', + label: '采购订单编号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入采购订单编号', + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '退货单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '退货单名称', + minWidth: 150, + }, + { + field: 'purchaseOrderCode', + title: '采购订单号', + minWidth: 140, + }, + { + field: 'vendorCode', + title: '供应商编码', + minWidth: 120, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 150, + }, + { + field: 'returnDate', + title: '退货日期', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_RETURN_VENDOR_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, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 退货单行新增/修改的表单 */ +export function useLineFormSchema( + vendorId?: number, + formApi?: VbenFormApi, +): 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: 'batchId', + label: '批次号', + component: markRaw(WmBatchSelect), + componentProps: { + // 选择批次后同步批次号 + onChange: async (batch?: { code?: string }) => { + await formApi?.setFieldValue('batchCode', batch?.code); + }, + vendorId, + }, + dependencies: { + triggerFields: ['itemId'], + componentProps: (values) => ({ + itemId: values.itemId, + vendorId, + }), + }, + }, + { + fieldName: 'batchCode', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} + +/** 拣货明细子表的字段 */ +export function useDetailGridColumns( + stockable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + { + 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: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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: '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/returnvendor/index.vue b/apps/web-ele/src/views/mes/wm/returnvendor/index.vue new file mode 100644 index 000000000..28e534d65 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/index.vue @@ -0,0 +1,211 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-form.vue new file mode 100644 index 000000000..fb1bff90e --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-list.vue new file mode 100644 index 000000000..11b5a8900 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnvendor/modules/form.vue b/apps/web-ele/src/views/mes/wm/returnvendor/modules/form.vue new file mode 100644 index 000000000..e35ca121b --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/modules/form.vue @@ -0,0 +1,244 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnvendor/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/returnvendor/modules/line-form.vue new file mode 100644 index 000000000..a31191f74 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/modules/line-form.vue @@ -0,0 +1,99 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/returnvendor/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/returnvendor/modules/line-list.vue new file mode 100644 index 000000000..b6586c6e7 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/returnvendor/modules/line-list.vue @@ -0,0 +1,235 @@ + + +