diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/components/index.ts b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/index.ts new file mode 100644 index 000000000..1da3df21b --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/index.ts @@ -0,0 +1,2 @@ +export { default as WmArrivalNoticeLineSelect } from './wm-arrival-notice-line-select.vue'; +export { default as WmArrivalNoticeSelect } from './wm-arrival-notice-select.vue'; diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select-dialog.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select-dialog.vue new file mode 100644 index 000000000..8081565ca --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select-dialog.vue @@ -0,0 +1,203 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select.vue new file mode 100644 index 000000000..e186f465f --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select.vue @@ -0,0 +1,151 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select-dialog.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select-dialog.vue new file mode 100644 index 000000000..176d9e158 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select-dialog.vue @@ -0,0 +1,262 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select.vue new file mode 100644 index 000000000..3858b7f13 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select.vue @@ -0,0 +1,138 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/data.ts b/apps/web-antd/src/views/mes/wm/arrivalnotice/data.ts new file mode 100644 index 000000000..973d83b38 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/data.ts @@ -0,0 +1,353 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice'; +import type { MesWmArrivalNoticeLineApi } from '#/api/mes/wm/arrivalnotice/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +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 { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 新增/修改的表单 */ +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: + formType === 'detail' + ? undefined + : () => + h( + Button, + { + type: 'default', + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_ARRIVAL_NOTICE_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: 'arrivalDate', + label: '到货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择到货日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'contactName', + label: '联系人', + component: 'Input', + componentProps: { + placeholder: '请输入联系人', + }, + }, + { + fieldName: 'contactTelephone', + 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: '请选择供应商', + }, + }, + { + fieldName: 'arrivalDate', + 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: 'purchaseOrderCode', + title: '采购订单编号', + minWidth: 140, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 120, + }, + { + field: 'contactName', + title: '联系人', + minWidth: 100, + }, + { + field: 'contactTelephone', + title: '联系方式', + minWidth: 120, + }, + { + field: 'arrivalDate', + title: '到货日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_ARRIVAL_NOTICE_STATUS }, + }, + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 通知单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'itemCode', + title: '物料编码', + minWidth: 120, + }, + { + field: 'itemName', + title: '物料名称', + minWidth: 140, + }, + { + field: 'specification', + title: '规格型号', + minWidth: 120, + }, + { + field: 'unitMeasureName', + title: '单位', + width: 80, + }, + { + field: 'arrivalQuantity', + title: '到货数量', + width: 100, + }, + { + field: 'iqcCheckFlag', + title: '是否检验', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualifiedQuantity', + title: '合格数量', + width: 100, + }, + { + field: 'iqcCode', + title: '检验单号', + minWidth: 140, + }, + { + field: 'remark', + title: '备注', + minWidth: 120, + }, + ...(editable + ? [ + { + title: '操作', + width: 120, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 通知单行新增/修改的表单 */ +export function useLineFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + }, + { + fieldName: 'arrivalQuantity', + label: '到货数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0.01, + placeholder: '请输入到货数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'iqcCheckFlag', + label: '是否检验', + component: 'Switch', + rules: z.boolean().default(false), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/index.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/index.vue new file mode 100644 index 000000000..33017a2de --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/index.vue @@ -0,0 +1,187 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/form.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/form.vue new file mode 100644 index 000000000..065d8af98 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/form.vue @@ -0,0 +1,168 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/line-form.vue new file mode 100644 index 000000000..cf9e4dd7f --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/line-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/line-list.vue new file mode 100644 index 000000000..b8276c13f --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/arrivalnotice/modules/line-list.vue @@ -0,0 +1,139 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/itemreceipt/data.ts b/apps/web-antd/src/views/mes/wm/itemreceipt/data.ts new file mode 100644 index 000000000..fcf5b0169 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/data.ts @@ -0,0 +1,530 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice'; +import type { MesWmArrivalNoticeLineApi } from '#/api/mes/wm/arrivalnotice/line'; +import type { MesWmItemReceiptApi } from '#/api/mes/wm/itemreceipt'; +import type { MesWmItemReceiptDetailApi } from '#/api/mes/wm/itemreceipt/detail'; +import type { MesWmItemReceiptLineApi } from '#/api/mes/wm/itemreceipt/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 { 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 { + MesAutoCodeRuleCode, + MesWmArrivalNoticeStatusEnum, +} from '#/views/mes/utils/constants'; +import { + WmArrivalNoticeLineSelect, + WmArrivalNoticeSelect, +} from '#/views/mes/wm/arrivalnotice/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_ITEM_RECEIPT_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入入库单名称', + }, + rules: 'required', + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择入库日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'noticeId', + label: '到货通知单', + component: markRaw(WmArrivalNoticeSelect), + componentProps: { + // 选择到货通知单后,自动回填供应商和采购订单号 + onChange: async (notice?: MesWmArrivalNoticeApi.ArrivalNotice) => { + await formApi?.setValues({ + purchaseOrderCode: notice?.purchaseOrderCode, + vendorId: notice?.vendorId, + }); + }, + status: MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT, + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + rules: 'selectRequired', + }, + { + fieldName: 'purchaseOrderCode', + 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: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + 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: 'purchaseOrderCode', + 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_ITEM_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: 'receivedQuantity', + title: '入库数量', + width: 100, + }, + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 入库单行新增/修改的表单 */ +export function useLineFormSchema( + hasNotice: boolean, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'noticeId', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'arrivalNoticeLineId', + label: '到货通知单行', + component: markRaw(WmArrivalNoticeLineSelect), + componentProps: { + // 选择到货通知单行后,自动回填物料和入库数量 + onChange: async ( + line?: MesWmArrivalNoticeLineApi.ArrivalNoticeLine, + ) => { + await formApi?.setValues({ + itemId: line?.itemId, + receivedQuantity: line?.arrivalQuantity, + }); + }, + }, + dependencies: { + triggerFields: ['noticeId'], + if: () => hasNotice, + componentProps: (values) => ({ + noticeId: values.noticeId, + }), + }, + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['arrivalNoticeLineId'], + componentProps: (values) => ({ + disabled: !!values.arrivalNoticeLineId, + placeholder: '请选择物料', + }), + }, + }, + { + fieldName: 'receivedQuantity', + label: '入库数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入入库数量', + precision: 2, + }, + rules: 'required', + }, + { + 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: '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: '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: '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/itemreceipt/index.vue b/apps/web-antd/src/views/mes/wm/itemreceipt/index.vue new file mode 100644 index 000000000..fa395a8e2 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/index.vue @@ -0,0 +1,209 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/itemreceipt/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/detail-form.vue new file mode 100644 index 000000000..c80e78798 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/itemreceipt/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/detail-list.vue new file mode 100644 index 000000000..7786e1463 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/itemreceipt/modules/form.vue b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/form.vue new file mode 100644 index 000000000..54fa26f86 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/form.vue @@ -0,0 +1,238 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/itemreceipt/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/line-form.vue new file mode 100644 index 000000000..debfc76c0 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/line-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/itemreceipt/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/line-list.vue new file mode 100644 index 000000000..0979185d9 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/itemreceipt/modules/line-list.vue @@ -0,0 +1,238 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productissue/data.ts b/apps/web-antd/src/views/mes/wm/productissue/data.ts new file mode 100644 index 000000000..5765e8ce3 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/data.ts @@ -0,0 +1,474 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmProductIssueApi } from '#/api/mes/wm/productissue'; +import type { MesWmProductIssueDetailApi } from '#/api/mes/wm/productissue/detail'; +import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +import { Button } from 'ant-design-vue'; + +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 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_PRODUCT_ISSUE_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '领料单名称', + component: 'Input', + componentProps: { + placeholder: '请输入领料单名称', + }, + rules: 'required', + }, + { + fieldName: 'requiredTime', + label: '需求时间', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择需求时间', + showTime: true, + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + rules: 'selectRequired', + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + 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: 'issueDate', + label: '领料日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + { + fieldName: 'status', + label: '单据状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_WM_PRODUCT_ISSUE_STATUS, 'number'), + placeholder: '请选择单据状态', + }, + }, + ]; +} + +/** 列表的字段 */ +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: 'workstationName', + title: '工作站', + minWidth: 120, + }, + { + field: 'requiredTime', + title: '需求时间', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_PRODUCT_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, + }, + ...(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', + min: 0, + placeholder: '请输入领料数量', + precision: 2, + }, + rules: 'required', + }, + { + 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/productissue/index.vue b/apps/web-antd/src/views/mes/wm/productissue/index.vue new file mode 100644 index 000000000..e3a2d8317 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/index.vue @@ -0,0 +1,227 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productissue/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/productissue/modules/detail-form.vue new file mode 100644 index 000000000..43faa4e2f --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productissue/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/productissue/modules/detail-list.vue new file mode 100644 index 000000000..21b81e6bd --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productissue/modules/form.vue b/apps/web-antd/src/views/mes/wm/productissue/modules/form.vue new file mode 100644 index 000000000..89118c038 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/modules/form.vue @@ -0,0 +1,229 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productissue/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/productissue/modules/line-form.vue new file mode 100644 index 000000000..8bf9782bc --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/modules/line-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productissue/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/productissue/modules/line-list.vue new file mode 100644 index 000000000..790d2cdc0 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productissue/modules/line-list.vue @@ -0,0 +1,220 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productreceipt/data.ts b/apps/web-antd/src/views/mes/wm/productreceipt/data.ts new file mode 100644 index 000000000..07f679212 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/data.ts @@ -0,0 +1,454 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmProductReceiptApi } from '#/api/mes/wm/productreceipt'; +import type { MesWmProductReceiptDetailApi } from '#/api/mes/wm/productreceipt/detail'; +import type { MesWmProductReceiptLineApi } from '#/api/mes/wm/productreceipt/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 { getRangePickerDefaultProps } from '#/utils'; +import MdItemSelect from '#/views/mes/md/item/components/md-item-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.PRODUCTRECPT_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入入库单名称', + }, + rules: 'required', + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择入库日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + }, + { + 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: '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: 'receiptDate', + title: '入库日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_PRODUCT_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, + }, + ...(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: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + placeholder: '选择库存后自动带出', + }, + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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: '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: '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/productreceipt/index.vue b/apps/web-antd/src/views/mes/wm/productreceipt/index.vue new file mode 100644 index 000000000..7ac6f90ac --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/index.vue @@ -0,0 +1,209 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productreceipt/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/productreceipt/modules/detail-form.vue new file mode 100644 index 000000000..b2a91c2b8 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productreceipt/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/productreceipt/modules/detail-list.vue new file mode 100644 index 000000000..a42bc868f --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productreceipt/modules/form.vue b/apps/web-antd/src/views/mes/wm/productreceipt/modules/form.vue new file mode 100644 index 000000000..5755163fa --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/modules/form.vue @@ -0,0 +1,235 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productreceipt/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/productreceipt/modules/line-form.vue new file mode 100644 index 000000000..b9e37161e --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/modules/line-form.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productreceipt/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/productreceipt/modules/line-list.vue new file mode 100644 index 000000000..de9d10081 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productreceipt/modules/line-list.vue @@ -0,0 +1,249 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productsales/data.ts b/apps/web-antd/src/views/mes/wm/productsales/data.ts new file mode 100644 index 000000000..d7fc5fa6a --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/data.ts @@ -0,0 +1,688 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmProductSalesApi } from '#/api/mes/wm/productsales'; +import type { MesWmProductSalesDetailApi } from '#/api/mes/wm/productsales/detail'; +import type { MesWmProductSalesLineApi } from '#/api/mes/wm/productsales/line'; +import type { MesWmSalesNoticeApi } from '#/api/mes/wm/salesnotice'; +import type { MesWmSalesNoticeLineApi } from '#/api/mes/wm/salesnotice/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 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, + MesWmSalesNoticeStatusEnum, +} from '#/views/mes/utils/constants'; +import { WmMaterialStockSelect } from '#/views/mes/wm/materialstock/components'; +import { + WmSalesNoticeLineSelect, + WmSalesNoticeSelect, +} from '#/views/mes/wm/salesnotice/components'; +import { + WmWarehouseAreaSelect, + WmWarehouseLocationSelect, + WmWarehouseSelect, +} from '#/views/mes/wm/warehouse/components'; + +/** 表单类型 */ +export type FormType = + | 'create' + | 'detail' + | 'finish' + | 'shipping' + | 'stock' + | 'update'; + +/** 表单头部是否只读(拣货、填写运单、出库、详情态) */ +function isHeaderReadonly(formType: FormType): boolean { + return ( + formType === 'detail' || + formType === 'finish' || + formType === 'shipping' || + formType === 'stock' + ); +} + +/** 是否展示运输信息 */ +export function showShippingInfo(formType: FormType): boolean { + return ( + formType === 'shipping' || formType === 'detail' || formType === 'finish' + ); +} + +/** 新增/修改的表单 */ +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_PRODUCT_SALES_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '出库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入出库单名称', + }, + rules: 'required', + }, + { + fieldName: 'noticeId', + label: '发货通知单', + component: markRaw(WmSalesNoticeSelect), + componentProps: { + // 选择发货通知单后,自动回填销售订单号、客户、收货人信息 + onChange: async (notice?: MesWmSalesNoticeApi.SalesNotice) => { + await formApi?.setValues({ + clientId: notice?.clientId, + contactAddress: notice?.recipientAddress, + contactName: notice?.recipientName, + contactTelephone: notice?.recipientTelephone, + salesOrderCode: notice?.salesOrderCode, + }); + }, + status: MesWmSalesNoticeStatusEnum.APPROVED, + }, + }, + { + fieldName: 'salesOrderCode', + label: '销售订单编号', + component: 'Input', + componentProps: { + placeholder: '请输入销售订单编号', + }, + }, + { + fieldName: 'salesDate', + label: '出库日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择出库日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + placeholder: '请选择客户', + }, + rules: 'selectRequired', + }, + { + fieldName: 'contactName', + label: '收货人', + component: 'Input', + componentProps: { + placeholder: '请输入收货人', + }, + }, + { + fieldName: 'contactTelephone', + label: '联系方式', + component: 'Input', + componentProps: { + placeholder: '请输入联系方式', + }, + }, + { + fieldName: 'contactAddress', + label: '收货地址', + component: 'Input', + componentProps: { + placeholder: '请输入收货地址', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + { + fieldName: 'carrier', + label: '承运商', + component: 'Input', + componentProps: { + disabled: formType !== 'shipping', + placeholder: '请输入承运商', + }, + dependencies: { + triggerFields: [''], + if: () => showShippingInfo(formType), + }, + }, + { + fieldName: 'shippingNumber', + label: '运输单号', + component: 'Input', + componentProps: { + disabled: formType !== 'shipping', + placeholder: '请输入运输单号', + }, + dependencies: { + triggerFields: [''], + if: () => showShippingInfo(formType), + }, + }, + ]; +} + +/** 列表的搜索表单 */ +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: 'salesDate', + label: '出库日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + allowClear: true, + }, + }, + { + fieldName: 'status', + label: '单据状态', + component: 'Select', + componentProps: { + allowClear: true, + options: getDictOptions(DICT_TYPE.MES_WM_PRODUCT_SALES_STATUS, 'number'), + placeholder: '请选择单据状态', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '出库单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '出库单名称', + minWidth: 150, + }, + { + field: 'noticeCode', + title: '发货通知单号', + minWidth: 160, + }, + { + field: 'salesOrderCode', + title: '销售订单编号', + minWidth: 160, + }, + { + field: 'clientCode', + title: '客户编码', + minWidth: 120, + }, + { + field: 'clientName', + title: '客户名称', + minWidth: 120, + }, + { + field: 'contactName', + title: '收货人', + minWidth: 100, + }, + { + field: 'carrier', + title: '承运商', + minWidth: 120, + }, + { + field: 'shippingNumber', + title: '运输单号', + minWidth: 160, + }, + { + field: 'salesDate', + title: '出库日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_PRODUCT_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: 'oqcCheckFlag', + title: '是否校验', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 150, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 出库单行新增/修改的表单 */ +export function useLineFormSchema( + hasNotice: boolean, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'noticeId', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'noticeLineId', + label: '发货通知单行', + component: markRaw(WmSalesNoticeLineSelect), + componentProps: { + // 选择发货通知单行后,自动回填物料、数量、批次、是否检验 + onChange: async (line?: MesWmSalesNoticeLineApi.SalesNoticeLine) => { + await formApi?.setValues({ + batchCode: line?.batchCode, + itemId: line?.itemId, + oqcCheckFlag: line?.oqcCheckFlag ?? false, + quantity: line?.quantity, + }); + }, + }, + dependencies: { + triggerFields: ['noticeId'], + if: () => hasNotice, + componentProps: (values) => ({ + noticeId: values.noticeId, + }), + }, + }, + { + fieldName: 'itemId', + label: '产品', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择产品', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['noticeLineId'], + componentProps: (values) => ({ + disabled: !!values.noticeLineId, + placeholder: '请选择产品', + }), + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + }, + { + fieldName: 'quantity', + label: '出库数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + min: 0, + placeholder: '请输入出库数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'oqcCheckFlag', + label: '是否校验', + component: 'RadioGroup', + componentProps: { + buttonStyle: 'solid', + optionType: 'button', + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + }, + rules: z.boolean().default(false), + }, + { + 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: 'batchId', + 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', 'batchId'], + componentProps: (values) => ({ + batchId: values.batchId, + 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/productsales/index.vue b/apps/web-antd/src/views/mes/wm/productsales/index.vue new file mode 100644 index 000000000..fce6f5cff --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/index.vue @@ -0,0 +1,223 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productsales/modules/detail-form.vue b/apps/web-antd/src/views/mes/wm/productsales/modules/detail-form.vue new file mode 100644 index 000000000..122c318cf --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/modules/detail-form.vue @@ -0,0 +1,110 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productsales/modules/detail-list.vue b/apps/web-antd/src/views/mes/wm/productsales/modules/detail-list.vue new file mode 100644 index 000000000..e9e8f5ea6 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productsales/modules/form.vue b/apps/web-antd/src/views/mes/wm/productsales/modules/form.vue new file mode 100644 index 000000000..cf0b15acb --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/modules/form.vue @@ -0,0 +1,266 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productsales/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/productsales/modules/line-form.vue new file mode 100644 index 000000000..d8470daa1 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/modules/line-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/productsales/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/productsales/modules/line-list.vue new file mode 100644 index 000000000..d98fe643d --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/productsales/modules/line-list.vue @@ -0,0 +1,233 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/components/index.ts b/apps/web-antd/src/views/mes/wm/salesnotice/components/index.ts new file mode 100644 index 000000000..0d5910b0e --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/components/index.ts @@ -0,0 +1,2 @@ +export { default as WmSalesNoticeLineSelect } from './wm-sales-notice-line-select.vue'; +export { default as WmSalesNoticeSelect } from './wm-sales-notice-select.vue'; diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select-dialog.vue b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select-dialog.vue new file mode 100644 index 000000000..fdd4c69fb --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select-dialog.vue @@ -0,0 +1,198 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select.vue b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select.vue new file mode 100644 index 000000000..df595918e --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select.vue @@ -0,0 +1,151 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-select-dialog.vue b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-select-dialog.vue new file mode 100644 index 000000000..7a7019833 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-select-dialog.vue @@ -0,0 +1,262 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-select.vue b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-select.vue new file mode 100644 index 000000000..13f72c6f3 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/components/wm-sales-notice-select.vue @@ -0,0 +1,138 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/data.ts b/apps/web-antd/src/views/mes/wm/salesnotice/data.ts new file mode 100644 index 000000000..6e30cada5 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/data.ts @@ -0,0 +1,363 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmSalesNoticeApi } from '#/api/mes/wm/salesnotice'; +import type { MesWmSalesNoticeLineApi } from '#/api/mes/wm/salesnotice/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +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'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'finish' | 'update'; + +/** 表单头部是否只读(详情、执行出库态) */ +function isHeaderReadonly(formType: FormType): boolean { + return formType === 'detail' || formType === 'finish'; +} + +/** 新增/修改的表单 */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + 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_SALES_NOTICE_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: 'salesDate', + label: '发货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择发货日期', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'recipientName', + label: '收货人', + component: 'Input', + componentProps: { + placeholder: '请输入收货人', + }, + }, + { + fieldName: 'recipientTelephone', + label: '联系方式', + component: 'Input', + componentProps: { + placeholder: '请输入联系方式', + }, + }, + { + fieldName: 'recipientAddress', + 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: 'salesOrderCode', + label: '销售订单编号', + component: 'Input', + componentProps: { + allowClear: true, + placeholder: '请输入销售订单编号', + }, + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + 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: 'clientName', + title: '客户名称', + minWidth: 120, + }, + { + field: 'salesDate', + title: '发货日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'recipientName', + title: '收货人', + minWidth: 100, + }, + { + field: 'recipientTelephone', + title: '联系方式', + minWidth: 120, + }, + { + field: 'recipientAddress', + title: '收货地址', + minWidth: 200, + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_SALES_NOTICE_STATUS }, + }, + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 通知单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + 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: 'oqcCheckFlag', + title: '是否检验', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 120, + }, + ...(editable + ? [ + { + title: '操作', + width: 120, + 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.01, + placeholder: '请输入发货数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + }, + { + fieldName: 'oqcCheckFlag', + label: '是否检验', + component: 'Switch', + rules: z.boolean().default(true), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/index.vue b/apps/web-antd/src/views/mes/wm/salesnotice/index.vue new file mode 100644 index 000000000..0faa7ac82 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/index.vue @@ -0,0 +1,176 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/modules/form.vue b/apps/web-antd/src/views/mes/wm/salesnotice/modules/form.vue new file mode 100644 index 000000000..ae1c5afad --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/modules/form.vue @@ -0,0 +1,179 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/modules/line-form.vue b/apps/web-antd/src/views/mes/wm/salesnotice/modules/line-form.vue new file mode 100644 index 000000000..f33e49a6b --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/modules/line-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-antd/src/views/mes/wm/salesnotice/modules/line-list.vue b/apps/web-antd/src/views/mes/wm/salesnotice/modules/line-list.vue new file mode 100644 index 000000000..27ee104f7 --- /dev/null +++ b/apps/web-antd/src/views/mes/wm/salesnotice/modules/line-list.vue @@ -0,0 +1,137 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/components/index.ts b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/index.ts new file mode 100644 index 000000000..1da3df21b --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/index.ts @@ -0,0 +1,2 @@ +export { default as WmArrivalNoticeLineSelect } from './wm-arrival-notice-line-select.vue'; +export { default as WmArrivalNoticeSelect } from './wm-arrival-notice-select.vue'; diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select-dialog.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select-dialog.vue new file mode 100644 index 000000000..1a12121cc --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select-dialog.vue @@ -0,0 +1,206 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select.vue new file mode 100644 index 000000000..2d2c482f6 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-line-select.vue @@ -0,0 +1,149 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select-dialog.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select-dialog.vue new file mode 100644 index 000000000..836078b64 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select-dialog.vue @@ -0,0 +1,265 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select.vue new file mode 100644 index 000000000..5c02fc81b --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/components/wm-arrival-notice-select.vue @@ -0,0 +1,136 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/data.ts b/apps/web-ele/src/views/mes/wm/arrivalnotice/data.ts new file mode 100644 index 000000000..210a6a37f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/data.ts @@ -0,0 +1,354 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice'; +import type { MesWmArrivalNoticeLineApi } from '#/api/mes/wm/arrivalnotice/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +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 { MesAutoCodeRuleCode } from '#/views/mes/utils/constants'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'update'; + +/** 新增/修改的表单 */ +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: + formType === 'detail' + ? undefined + : () => + h( + ElButton, + { + onClick: async () => { + const code = await generateAutoCode( + MesAutoCodeRuleCode.WM_ARRIVAL_NOTICE_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: 'arrivalDate', + label: '到货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择到货日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'contactName', + label: '联系人', + component: 'Input', + componentProps: { + placeholder: '请输入联系人', + }, + }, + { + fieldName: 'contactTelephone', + 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: '请选择供应商', + }, + }, + { + fieldName: 'arrivalDate', + 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: 'purchaseOrderCode', + title: '采购订单编号', + minWidth: 140, + }, + { + field: 'vendorName', + title: '供应商名称', + minWidth: 120, + }, + { + field: 'contactName', + title: '联系人', + minWidth: 100, + }, + { + field: 'contactTelephone', + title: '联系方式', + minWidth: 120, + }, + { + field: 'arrivalDate', + title: '到货日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_ARRIVAL_NOTICE_STATUS }, + }, + }, + { + title: '操作', + width: 180, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 通知单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + field: 'itemCode', + title: '物料编码', + minWidth: 120, + }, + { + field: 'itemName', + title: '物料名称', + minWidth: 140, + }, + { + field: 'specification', + title: '规格型号', + minWidth: 120, + }, + { + field: 'unitMeasureName', + title: '单位', + width: 80, + }, + { + field: 'arrivalQuantity', + title: '到货数量', + width: 100, + }, + { + field: 'iqcCheckFlag', + title: '是否检验', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'qualifiedQuantity', + title: '合格数量', + width: 100, + }, + { + field: 'iqcCode', + title: '检验单号', + minWidth: 140, + }, + { + field: 'remark', + title: '备注', + minWidth: 120, + }, + ...(editable + ? [ + { + title: '操作', + width: 120, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 通知单行新增/修改的表单 */ +export function useLineFormSchema(): VbenFormSchema[] { + return [ + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + }, + { + fieldName: 'arrivalQuantity', + label: '到货数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0.01, + placeholder: '请输入到货数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'iqcCheckFlag', + label: '是否检验', + component: 'Switch', + rules: z.boolean().default(false), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/index.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/index.vue new file mode 100644 index 000000000..041c6a27a --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/index.vue @@ -0,0 +1,189 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/form.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/form.vue new file mode 100644 index 000000000..4014f8593 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/form.vue @@ -0,0 +1,171 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/line-form.vue new file mode 100644 index 000000000..61712f6ff --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/line-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/line-list.vue new file mode 100644 index 000000000..4b38709cc --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/arrivalnotice/modules/line-list.vue @@ -0,0 +1,139 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/itemreceipt/data.ts b/apps/web-ele/src/views/mes/wm/itemreceipt/data.ts new file mode 100644 index 000000000..a812f6857 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/data.ts @@ -0,0 +1,534 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmArrivalNoticeApi } from '#/api/mes/wm/arrivalnotice'; +import type { MesWmArrivalNoticeLineApi } from '#/api/mes/wm/arrivalnotice/line'; +import type { MesWmItemReceiptApi } from '#/api/mes/wm/itemreceipt'; +import type { MesWmItemReceiptDetailApi } from '#/api/mes/wm/itemreceipt/detail'; +import type { MesWmItemReceiptLineApi } from '#/api/mes/wm/itemreceipt/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 { + MesAutoCodeRuleCode, + MesWmArrivalNoticeStatusEnum, +} from '#/views/mes/utils/constants'; +import { + WmArrivalNoticeLineSelect, + WmArrivalNoticeSelect, +} from '#/views/mes/wm/arrivalnotice/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_ITEM_RECEIPT_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入入库单名称', + }, + rules: 'required', + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择入库日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'noticeId', + label: '到货通知单', + component: markRaw(WmArrivalNoticeSelect), + componentProps: { + // 选择到货通知单后,自动回填供应商和采购订单号 + onChange: async (notice?: MesWmArrivalNoticeApi.ArrivalNotice) => { + await formApi?.setValues({ + purchaseOrderCode: notice?.purchaseOrderCode, + vendorId: notice?.vendorId, + }); + }, + status: MesWmArrivalNoticeStatusEnum.PENDING_RECEIPT, + }, + }, + { + fieldName: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + placeholder: '请选择供应商', + }, + rules: 'selectRequired', + }, + { + fieldName: 'purchaseOrderCode', + 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: 'vendorId', + label: '供应商', + component: markRaw(MdVendorSelect), + componentProps: { + 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: 'purchaseOrderCode', + 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_ITEM_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: 'receivedQuantity', + title: '入库数量', + width: 100, + }, + { + field: 'batchCode', + title: '批次号', + minWidth: 120, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 入库单行新增/修改的表单 */ +export function useLineFormSchema( + hasNotice: boolean, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'noticeId', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'arrivalNoticeLineId', + label: '到货通知单行', + component: markRaw(WmArrivalNoticeLineSelect), + componentProps: { + // 选择到货通知单行后,自动回填物料和入库数量 + onChange: async ( + line?: MesWmArrivalNoticeLineApi.ArrivalNoticeLine, + ) => { + await formApi?.setValues({ + itemId: line?.itemId, + receivedQuantity: line?.arrivalQuantity, + }); + }, + }, + dependencies: { + triggerFields: ['noticeId'], + if: () => hasNotice, + componentProps: (values) => ({ + noticeId: values.noticeId, + }), + }, + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择物料', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['arrivalNoticeLineId'], + componentProps: (values) => ({ + disabled: !!values.arrivalNoticeLineId, + placeholder: '请选择物料', + }), + }, + }, + { + fieldName: 'receivedQuantity', + label: '入库数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入入库数量', + precision: 2, + }, + rules: 'required', + }, + { + 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: '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: '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: '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/itemreceipt/index.vue b/apps/web-ele/src/views/mes/wm/itemreceipt/index.vue new file mode 100644 index 000000000..06a610b68 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/index.vue @@ -0,0 +1,211 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/itemreceipt/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/detail-form.vue new file mode 100644 index 000000000..e1a062a41 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/itemreceipt/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/detail-list.vue new file mode 100644 index 000000000..b03aa6762 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/itemreceipt/modules/form.vue b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/form.vue new file mode 100644 index 000000000..a67a42031 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/form.vue @@ -0,0 +1,241 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/itemreceipt/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/line-form.vue new file mode 100644 index 000000000..673bde942 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/line-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/itemreceipt/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/line-list.vue new file mode 100644 index 000000000..4f4f8d9b9 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/itemreceipt/modules/line-list.vue @@ -0,0 +1,239 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productissue/data.ts b/apps/web-ele/src/views/mes/wm/productissue/data.ts new file mode 100644 index 000000000..6891918e0 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/data.ts @@ -0,0 +1,476 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmProductIssueApi } from '#/api/mes/wm/productissue'; +import type { MesWmProductIssueDetailApi } from '#/api/mes/wm/productissue/detail'; +import type { MesWmProductIssueLineApi } from '#/api/mes/wm/productissue/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; +import { getDictOptions } from '@vben/hooks'; + +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 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_PRODUCT_ISSUE_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '领料单名称', + component: 'Input', + componentProps: { + placeholder: '请输入领料单名称', + }, + rules: 'required', + }, + { + fieldName: 'requiredTime', + label: '需求时间', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD HH:mm:ss', + placeholder: '请选择需求时间', + type: 'datetime', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + rules: 'selectRequired', + }, + { + fieldName: 'workstationId', + label: '工作站', + component: markRaw(MdWorkstationSelect), + 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: 'issueDate', + label: '领料日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + { + fieldName: 'status', + label: '单据状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_WM_PRODUCT_ISSUE_STATUS, 'number'), + placeholder: '请选择单据状态', + }, + }, + ]; +} + +/** 列表的字段 */ +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: 'workstationName', + title: '工作站', + minWidth: 120, + }, + { + field: 'requiredTime', + title: '需求时间', + width: 180, + formatter: 'formatDateTime', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_PRODUCT_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, + }, + ...(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: '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/productissue/index.vue b/apps/web-ele/src/views/mes/wm/productissue/index.vue new file mode 100644 index 000000000..c1e8bb461 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/index.vue @@ -0,0 +1,230 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productissue/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/productissue/modules/detail-form.vue new file mode 100644 index 000000000..785c8ee0b --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productissue/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/productissue/modules/detail-list.vue new file mode 100644 index 000000000..548fd75fc --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productissue/modules/form.vue b/apps/web-ele/src/views/mes/wm/productissue/modules/form.vue new file mode 100644 index 000000000..a5dc6f97c --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/modules/form.vue @@ -0,0 +1,235 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productissue/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/productissue/modules/line-form.vue new file mode 100644 index 000000000..f2e455ff5 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/modules/line-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productissue/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/productissue/modules/line-list.vue new file mode 100644 index 000000000..a40376788 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productissue/modules/line-list.vue @@ -0,0 +1,221 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productreceipt/data.ts b/apps/web-ele/src/views/mes/wm/productreceipt/data.ts new file mode 100644 index 000000000..159c99407 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/data.ts @@ -0,0 +1,457 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmProductReceiptApi } from '#/api/mes/wm/productreceipt'; +import type { MesWmProductReceiptDetailApi } from '#/api/mes/wm/productreceipt/detail'; +import type { MesWmProductReceiptLineApi } from '#/api/mes/wm/productreceipt/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 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.PRODUCTRECPT_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '入库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入入库单名称', + }, + rules: 'required', + }, + { + fieldName: 'receiptDate', + label: '入库日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择入库日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'workOrderId', + label: '生产工单', + component: markRaw(ProWorkOrderSelect), + componentProps: { + status: MesProWorkOrderStatusEnum.CONFIRMED, + }, + }, + { + 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: '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: 'receiptDate', + title: '入库日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 110, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_PRODUCT_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, + }, + ...(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: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + disabled: true, + placeholder: '选择库存后自动带出', + }, + }, + { + fieldName: 'itemId', + label: '物料', + component: markRaw(MdItemSelect), + componentProps: { + disabled: true, + }, + }, + { + 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: '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: '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/productreceipt/index.vue b/apps/web-ele/src/views/mes/wm/productreceipt/index.vue new file mode 100644 index 000000000..14b8902cc --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/index.vue @@ -0,0 +1,211 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productreceipt/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/productreceipt/modules/detail-form.vue new file mode 100644 index 000000000..bbdaa353a --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/modules/detail-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productreceipt/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/productreceipt/modules/detail-list.vue new file mode 100644 index 000000000..f80b8b42f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productreceipt/modules/form.vue b/apps/web-ele/src/views/mes/wm/productreceipt/modules/form.vue new file mode 100644 index 000000000..9da8463bc --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/modules/form.vue @@ -0,0 +1,238 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productreceipt/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/productreceipt/modules/line-form.vue new file mode 100644 index 000000000..66676b96d --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/modules/line-form.vue @@ -0,0 +1,95 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productreceipt/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/productreceipt/modules/line-list.vue new file mode 100644 index 000000000..49acca838 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productreceipt/modules/line-list.vue @@ -0,0 +1,251 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productsales/data.ts b/apps/web-ele/src/views/mes/wm/productsales/data.ts new file mode 100644 index 000000000..eeee968b1 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/data.ts @@ -0,0 +1,689 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmMaterialStockApi } from '#/api/mes/wm/materialstock'; +import type { MesWmProductSalesApi } from '#/api/mes/wm/productsales'; +import type { MesWmProductSalesDetailApi } from '#/api/mes/wm/productsales/detail'; +import type { MesWmProductSalesLineApi } from '#/api/mes/wm/productsales/line'; +import type { MesWmSalesNoticeApi } from '#/api/mes/wm/salesnotice'; +import type { MesWmSalesNoticeLineApi } from '#/api/mes/wm/salesnotice/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 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, + MesWmSalesNoticeStatusEnum, +} from '#/views/mes/utils/constants'; +import { WmMaterialStockSelect } from '#/views/mes/wm/materialstock/components'; +import { + WmSalesNoticeLineSelect, + WmSalesNoticeSelect, +} from '#/views/mes/wm/salesnotice/components'; +import { + WmWarehouseAreaSelect, + WmWarehouseLocationSelect, + WmWarehouseSelect, +} from '#/views/mes/wm/warehouse/components'; + +/** 表单类型 */ +export type FormType = + | 'create' + | 'detail' + | 'finish' + | 'shipping' + | 'stock' + | 'update'; + +/** 表单头部是否只读(拣货、填写运单、出库、详情态) */ +function isHeaderReadonly(formType: FormType): boolean { + return ( + formType === 'detail' || + formType === 'finish' || + formType === 'shipping' || + formType === 'stock' + ); +} + +/** 是否展示运输信息 */ +export function showShippingInfo(formType: FormType): boolean { + return ( + formType === 'shipping' || formType === 'detail' || formType === 'finish' + ); +} + +/** 新增/修改的表单 */ +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_PRODUCT_SALES_CODE, + ); + await formApi?.setFieldValue('code', code); + }, + }, + { default: () => '生成' }, + ), + }, + { + fieldName: 'name', + label: '出库单名称', + component: 'Input', + componentProps: { + placeholder: '请输入出库单名称', + }, + rules: 'required', + }, + { + fieldName: 'noticeId', + label: '发货通知单', + component: markRaw(WmSalesNoticeSelect), + componentProps: { + // 选择发货通知单后,自动回填销售订单号、客户、收货人信息 + onChange: async (notice?: MesWmSalesNoticeApi.SalesNotice) => { + await formApi?.setValues({ + clientId: notice?.clientId, + contactAddress: notice?.recipientAddress, + contactName: notice?.recipientName, + contactTelephone: notice?.recipientTelephone, + salesOrderCode: notice?.salesOrderCode, + }); + }, + status: MesWmSalesNoticeStatusEnum.APPROVED, + }, + }, + { + fieldName: 'salesOrderCode', + label: '销售订单编号', + component: 'Input', + componentProps: { + placeholder: '请输入销售订单编号', + }, + }, + { + fieldName: 'salesDate', + label: '出库日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择出库日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + placeholder: '请选择客户', + }, + rules: 'selectRequired', + }, + { + fieldName: 'contactName', + label: '收货人', + component: 'Input', + componentProps: { + placeholder: '请输入收货人', + }, + }, + { + fieldName: 'contactTelephone', + label: '联系方式', + component: 'Input', + componentProps: { + placeholder: '请输入联系方式', + }, + }, + { + fieldName: 'contactAddress', + label: '收货地址', + component: 'Input', + componentProps: { + placeholder: '请输入收货地址', + }, + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + { + fieldName: 'carrier', + label: '承运商', + component: 'Input', + componentProps: { + disabled: formType !== 'shipping', + placeholder: '请输入承运商', + }, + dependencies: { + triggerFields: [''], + if: () => showShippingInfo(formType), + }, + }, + { + fieldName: 'shippingNumber', + label: '运输单号', + component: 'Input', + componentProps: { + disabled: formType !== 'shipping', + placeholder: '请输入运输单号', + }, + dependencies: { + triggerFields: [''], + if: () => showShippingInfo(formType), + }, + }, + ]; +} + +/** 列表的搜索表单 */ +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: 'salesDate', + label: '出库日期', + component: 'RangePicker', + componentProps: { + ...getRangePickerDefaultProps(), + clearable: true, + }, + }, + { + fieldName: 'status', + label: '单据状态', + component: 'Select', + componentProps: { + clearable: true, + options: getDictOptions(DICT_TYPE.MES_WM_PRODUCT_SALES_STATUS, 'number'), + placeholder: '请选择单据状态', + }, + }, + ]; +} + +/** 列表的字段 */ +export function useGridColumns(): VxeTableGridOptions['columns'] { + return [ + { + field: 'code', + title: '出库单编号', + minWidth: 160, + slots: { default: 'code' }, + }, + { + field: 'name', + title: '出库单名称', + minWidth: 150, + }, + { + field: 'noticeCode', + title: '发货通知单号', + minWidth: 160, + }, + { + field: 'salesOrderCode', + title: '销售订单编号', + minWidth: 160, + }, + { + field: 'clientCode', + title: '客户编码', + minWidth: 120, + }, + { + field: 'clientName', + title: '客户名称', + minWidth: 120, + }, + { + field: 'contactName', + title: '收货人', + minWidth: 100, + }, + { + field: 'carrier', + title: '承运商', + minWidth: 120, + }, + { + field: 'shippingNumber', + title: '运输单号', + minWidth: 160, + }, + { + field: 'salesDate', + title: '出库日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_PRODUCT_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: 'oqcCheckFlag', + title: '是否校验', + width: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 150, + }, + ...(editable || stockable + ? [ + { + title: '操作', + width: 160, + fixed: 'right', + slots: { default: 'actions' }, + } as const, + ] + : []), + ]; +} + +/** 出库单行新增/修改的表单 */ +export function useLineFormSchema( + hasNotice: boolean, + formApi?: VbenFormApi, +): VbenFormSchema[] { + return [ + { + fieldName: 'noticeId', + component: 'Input', + dependencies: { + triggerFields: [''], + show: () => false, + }, + }, + { + fieldName: 'noticeLineId', + label: '发货通知单行', + component: markRaw(WmSalesNoticeLineSelect), + componentProps: { + // 选择发货通知单行后,自动回填物料、数量、批次、是否检验 + onChange: async (line?: MesWmSalesNoticeLineApi.SalesNoticeLine) => { + await formApi?.setValues({ + batchCode: line?.batchCode, + itemId: line?.itemId, + oqcCheckFlag: line?.oqcCheckFlag ?? false, + quantity: line?.quantity, + }); + }, + }, + dependencies: { + triggerFields: ['noticeId'], + if: () => hasNotice, + componentProps: (values) => ({ + noticeId: values.noticeId, + }), + }, + }, + { + fieldName: 'itemId', + label: '产品', + component: markRaw(MdItemSelect), + componentProps: { + placeholder: '请选择产品', + }, + rules: 'selectRequired', + dependencies: { + triggerFields: ['noticeLineId'], + componentProps: (values) => ({ + disabled: !!values.noticeLineId, + placeholder: '请选择产品', + }), + }, + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + }, + { + fieldName: 'quantity', + label: '出库数量', + component: 'InputNumber', + componentProps: { + class: '!w-full', + controlsPosition: 'right', + min: 0, + placeholder: '请输入出库数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'oqcCheckFlag', + label: '是否校验', + component: 'RadioGroup', + componentProps: { + options: getDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING, 'boolean'), + }, + rules: z.boolean().default(false), + }, + { + 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: 'batchId', + 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', 'batchId'], + componentProps: (values) => ({ + batchId: values.batchId, + 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/productsales/index.vue b/apps/web-ele/src/views/mes/wm/productsales/index.vue new file mode 100644 index 000000000..fef659867 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/index.vue @@ -0,0 +1,226 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productsales/modules/detail-form.vue b/apps/web-ele/src/views/mes/wm/productsales/modules/detail-form.vue new file mode 100644 index 000000000..0451936dd --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/modules/detail-form.vue @@ -0,0 +1,110 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productsales/modules/detail-list.vue b/apps/web-ele/src/views/mes/wm/productsales/modules/detail-list.vue new file mode 100644 index 000000000..4efd48aca --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/modules/detail-list.vue @@ -0,0 +1,103 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productsales/modules/form.vue b/apps/web-ele/src/views/mes/wm/productsales/modules/form.vue new file mode 100644 index 000000000..d92ea8336 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/modules/form.vue @@ -0,0 +1,275 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productsales/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/productsales/modules/line-form.vue new file mode 100644 index 000000000..44d1a7ec9 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/modules/line-form.vue @@ -0,0 +1,104 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/productsales/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/productsales/modules/line-list.vue new file mode 100644 index 000000000..339d1f24f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/productsales/modules/line-list.vue @@ -0,0 +1,234 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/components/index.ts b/apps/web-ele/src/views/mes/wm/salesnotice/components/index.ts new file mode 100644 index 000000000..0d5910b0e --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/components/index.ts @@ -0,0 +1,2 @@ +export { default as WmSalesNoticeLineSelect } from './wm-sales-notice-line-select.vue'; +export { default as WmSalesNoticeSelect } from './wm-sales-notice-select.vue'; diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select-dialog.vue b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select-dialog.vue new file mode 100644 index 000000000..e10f08af2 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select-dialog.vue @@ -0,0 +1,201 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select.vue b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select.vue new file mode 100644 index 000000000..87dd28dd2 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-line-select.vue @@ -0,0 +1,149 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-select-dialog.vue b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-select-dialog.vue new file mode 100644 index 000000000..d3d4c351f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-select-dialog.vue @@ -0,0 +1,265 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-select.vue b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-select.vue new file mode 100644 index 000000000..d1d5d80a0 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/components/wm-sales-notice-select.vue @@ -0,0 +1,136 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/data.ts b/apps/web-ele/src/views/mes/wm/salesnotice/data.ts new file mode 100644 index 000000000..35c0c8512 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/data.ts @@ -0,0 +1,364 @@ +import type { VbenFormApi, VbenFormSchema } from '#/adapter/form'; +import type { VxeTableGridOptions } from '#/adapter/vxe-table'; +import type { MesWmSalesNoticeApi } from '#/api/mes/wm/salesnotice'; +import type { MesWmSalesNoticeLineApi } from '#/api/mes/wm/salesnotice/line'; + +import { h, markRaw } from 'vue'; + +import { DICT_TYPE } from '@vben/constants'; + +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'; + +/** 表单类型 */ +export type FormType = 'create' | 'detail' | 'finish' | 'update'; + +/** 表单头部是否只读(详情、执行出库态) */ +function isHeaderReadonly(formType: FormType): boolean { + return formType === 'detail' || formType === 'finish'; +} + +/** 新增/修改的表单 */ +export function useFormSchema( + formType: FormType, + formApi?: VbenFormApi, +): VbenFormSchema[] { + 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_SALES_NOTICE_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: 'salesDate', + label: '发货日期', + component: 'DatePicker', + componentProps: { + class: '!w-full', + format: 'YYYY-MM-DD', + placeholder: '请选择发货日期', + type: 'date', + valueFormat: 'x', + }, + rules: 'required', + }, + { + fieldName: 'recipientName', + label: '收货人', + component: 'Input', + componentProps: { + placeholder: '请输入收货人', + }, + }, + { + fieldName: 'recipientTelephone', + label: '联系方式', + component: 'Input', + componentProps: { + placeholder: '请输入联系方式', + }, + }, + { + fieldName: 'recipientAddress', + 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: 'salesOrderCode', + label: '销售订单编号', + component: 'Input', + componentProps: { + clearable: true, + placeholder: '请输入销售订单编号', + }, + }, + { + fieldName: 'clientId', + label: '客户', + component: markRaw(MdClientSelect), + componentProps: { + 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: 'clientName', + title: '客户名称', + minWidth: 120, + }, + { + field: 'salesDate', + title: '发货日期', + width: 180, + formatter: 'formatDate', + }, + { + field: 'recipientName', + title: '收货人', + minWidth: 100, + }, + { + field: 'recipientTelephone', + title: '联系方式', + minWidth: 120, + }, + { + field: 'recipientAddress', + title: '收货地址', + minWidth: 200, + }, + { + field: 'status', + title: '单据状态', + minWidth: 100, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.MES_WM_SALES_NOTICE_STATUS }, + }, + }, + { + title: '操作', + width: 200, + fixed: 'right', + slots: { default: 'actions' }, + }, + ]; +} + +/** 通知单行子表的字段 */ +export function useLineGridColumns( + editable: boolean, +): VxeTableGridOptions['columns'] { + return [ + { + 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: 'oqcCheckFlag', + title: '是否检验', + width: 90, + cellRender: { + name: 'CellDict', + props: { type: DICT_TYPE.INFRA_BOOLEAN_STRING }, + }, + }, + { + field: 'remark', + title: '备注', + minWidth: 120, + }, + ...(editable + ? [ + { + title: '操作', + width: 120, + 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.01, + placeholder: '请输入发货数量', + precision: 2, + }, + rules: 'required', + }, + { + fieldName: 'batchCode', + label: '批次号', + component: 'Input', + componentProps: { + placeholder: '请输入批次号', + }, + }, + { + fieldName: 'oqcCheckFlag', + label: '是否检验', + component: 'Switch', + rules: z.boolean().default(true), + }, + { + fieldName: 'remark', + label: '备注', + component: 'Textarea', + formItemClass: 'col-span-3', + componentProps: { + placeholder: '请输入备注', + rows: 3, + }, + }, + ]; +} diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/index.vue b/apps/web-ele/src/views/mes/wm/salesnotice/index.vue new file mode 100644 index 000000000..14e72784f --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/index.vue @@ -0,0 +1,177 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/modules/form.vue b/apps/web-ele/src/views/mes/wm/salesnotice/modules/form.vue new file mode 100644 index 000000000..3a1f1258c --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/modules/form.vue @@ -0,0 +1,182 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/modules/line-form.vue b/apps/web-ele/src/views/mes/wm/salesnotice/modules/line-form.vue new file mode 100644 index 000000000..184a78728 --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/modules/line-form.vue @@ -0,0 +1,94 @@ + + + diff --git a/apps/web-ele/src/views/mes/wm/salesnotice/modules/line-list.vue b/apps/web-ele/src/views/mes/wm/salesnotice/modules/line-list.vue new file mode 100644 index 000000000..bf60f802a --- /dev/null +++ b/apps/web-ele/src/views/mes/wm/salesnotice/modules/line-list.vue @@ -0,0 +1,137 @@ + + +