feat(mes): 添加盘号字段并优化权限控制
- 在MES生产任务、质检、批次管理等相关模块中添加盘号(reelNo)字段显示
- 优化业务卡片权限控制逻辑,移除冗余的查询权限验证
- 更新销售明细、退货、调拨等业务流程中的盘号相关数据结构
- 修复退货销售表单中物料选择重复数据处理逻辑
- 移除多个页面中冗余的权限验证配置项
- 优化销售通知单、产品销售等界面的盘号显示功能
| | |
| | | itemSpecification?: string; // 规格型号(关联查询) |
| | | unitName?: string; // 单位名称(关联查询) |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 退货批次盘号 |
| | | checkQuantity?: number; // 检测数量 |
| | | qualifiedQuantity?: number; // 合格品数量 |
| | | unqualifiedQuantity?: number; // 不合格数量 |
| | |
| | | export interface Batch { |
| | | id?: number; // 批次 ID |
| | | code?: string; // 批次编码 |
| | | reelNo?: string; // 生产追溯盘号 |
| | | itemId?: number; // 物料 ID |
| | | itemCode?: string; // 物料编码 |
| | | itemName?: string; // 物料名称 |
| | |
| | | materialStockId?: number; // 库存记录编号 |
| | | batchId?: number; // 批次编号 |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 实际拣货库存盘号 |
| | | warehouseId?: number; // 仓库编号 |
| | | warehouseName?: string; // 仓库名称 |
| | | locationId?: number; // 库区编号 |
| | |
| | | pickedQuantity?: number; // 已拣货数量 |
| | | batchId?: number; // 批次编号 |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 销售明细盘号 |
| | | oqcCheckFlag?: boolean; // 是否检验 |
| | | remark?: string; // 备注 |
| | | } |
| | |
| | | quantity?: number; // 数量 |
| | | batchId?: number; // 批次编号 |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 上架批次盘号 |
| | | warehouseId?: number; // 仓库编号 |
| | | warehouseName?: string; // 仓库名称 |
| | | locationId?: number; // 库区编号 |
| | |
| | | quantity?: number; // 退货数量 |
| | | batchId?: number; // 批次编号 |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 退货批次盘号 |
| | | rqcCheckFlag?: boolean; // 是否需要质检 |
| | | rqcId?: number; // 退货检验单编号 |
| | | qualityStatus?: number; // 质量状态 |
| | |
| | | unitMeasureName?: string; // 单位 |
| | | batchId?: number; // 批次编号 |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 销售明细盘号 |
| | | quantity?: number; // 发货数量 |
| | | outCount?: number; // 已出库数量 |
| | | oqcCheckFlag?: boolean; // 是否检验 |
| | |
| | | quantity?: number; // 转移数量 |
| | | batchId?: number; // 批次编号 |
| | | batchCode?: string; // 批次号 |
| | | reelNo?: string; // 调拨批次盘号 |
| | | fromWarehouseId?: number; // 移出仓库编号 |
| | | fromWarehouseName?: string; // 移出仓库名称 |
| | | fromLocationId?: number; // 移出库区编号 |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['bpm:form:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['bpm:oa-notice:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['bpm:task:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: '办理', |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['bpm:task:query'], |
| | | onClick: handleAudit.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | const saleCount = ref(0); |
| | | const stockCount = ref(0); |
| | | const bpmTodoCount = ref(0); |
| | | const { canNavigate, canQuery } = useHomeAccess(); |
| | | const canViewPurchase = computed(() => canQuery('erp:purchase-order:query') && canNavigate('ErpPurchaseOrder')); |
| | | const canViewSale = computed(() => canQuery('erp:sale-order:query') && canNavigate('ErpSaleOrder')); |
| | | const canViewStock = computed(() => canQuery('mes:wm-material-stock:query') && canNavigate('MesWmMaterialStock')); |
| | | const canViewBpmTodo = computed(() => canQuery('bpm:task:query') && canNavigate('BpmTaskTodo')); |
| | | const { canNavigate } = useHomeAccess(); |
| | | const canViewPurchase = computed(() => canNavigate('ErpPurchaseOrder')); |
| | | const canViewSale = computed(() => canNavigate('ErpSaleOrder')); |
| | | const canViewStock = computed(() => canNavigate('MesWmMaterialStock')); |
| | | const canViewBpmTodo = computed(() => canNavigate('BpmTaskTodo')); |
| | | |
| | | async function loadPurchase() { |
| | | if (!canViewPurchase.value) return; |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:finance-payment:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:finance-receipt:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['finance:voucher:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:purchase-invoice:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:purchase-order:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:purchase-request:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['erp:sale-order:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | | label: '打印', |
| | | type: 'link', |
| | | icon: 'lucide:printer', |
| | | auth: ['erp:sale-order:query'], |
| | | onClick: handlePrint.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: '审批进度', |
| | | type: 'link', |
| | | icon: 'lucide:file-clock', |
| | | auth: ['erp:sale-order:query'], |
| | | ifShow: () => row.status === 15 && !!row.processInstanceId, |
| | | onClick: handleViewApproval.bind(null, row), |
| | | }, |
| | |
| | | label: '详情', |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['im:manager:group:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: '详情', |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['im:manager:message:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: '详情', |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['im:manager:message:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: '详情', |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['im:manager:rtc:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['infra:api-access-log:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['infra:api-error-log:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | auth: ['infra:job:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['infra:job:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:dv-check-record:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:dv-machinery:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:dv-mainten-record:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:dv-metering:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:dv-metering-check:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:dv-repair:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | { |
| | | label: '详情', |
| | | type: 'link', |
| | | auth: ['mes:pro-andon-record:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | width: 140, |
| | | }, |
| | | { |
| | | field: 'reelNo', |
| | | title: '盘号', |
| | | minWidth: 140, |
| | | }, |
| | | { |
| | | field: 'productCode', |
| | | title: '产品编码', |
| | | width: 120, |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'reelNo', |
| | | label: '盘号', |
| | | component: 'Input', |
| | | componentProps: { |
| | | disabled: true, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'type', |
| | | label: '订单类型', |
| | | component: 'Select', |
| | |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | fieldName: 'statusLabel', |
| | | label: '订单状态', |
| | | component: 'Select', |
| | | component: 'Input', |
| | | componentProps: { |
| | | disabled: true, |
| | | options: getDictOptions(DICT_TYPE.MES_PRO_WORK_ORDER_STATUS, 'number'), |
| | | }, |
| | | }, |
| | | { |
| | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | import { DICT_TYPE } from '@vben/constants'; |
| | | import { getDictLabel } from '@vben/hooks'; |
| | | |
| | | import { Button, Card, message, Popconfirm, Steps } from 'ant-design-vue'; |
| | | |
| | |
| | | try { |
| | | workOrder.value = await getWorkOrder(data.id); |
| | | // 设置到 values |
| | | await formApi.setValues(workOrder.value); |
| | | await formApi.setValues({ |
| | | ...workOrder.value, |
| | | statusLabel: workOrder.value.status == null |
| | | ? '-' |
| | | : getDictLabel(DICT_TYPE.MES_PRO_WORK_ORDER_STATUS, workOrder.value.status) || '-', |
| | | }); |
| | | if (workOrder.value.productId) { |
| | | await loadRouteProcesses( |
| | | workOrder.value.id!, |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:qc-ipqc:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:qc-iqc:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:qc-oqc:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | title: '批次号', |
| | | width: 130, |
| | | }, |
| | | { field: 'reelNo', title: '盘号', width: 130 }, |
| | | { |
| | | field: 'checkResult', |
| | | title: '检测结果', |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['mes:qc-rqc:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | const tabItems: WorkbenchTabItem[] = [ |
| | | { key: 'detail', label: '工单详情', icon: 'lucide:file-text' }, |
| | | { key: 'feedback', label: '报工', icon: 'lucide:edit-3', auth: ['mes:pro-feedback:create'] }, |
| | | { key: 'history', label: '报工记录', icon: 'lucide:history' ,auth: ['mes:pro-feedback:query']}, |
| | | { key: 'history', label: '报工记录', icon: 'lucide:history' }, |
| | | { key: 'record-param', label: '生产记录参数', icon: 'lucide:file-cog' }, |
| | | { key: 'product-issue', label: '领料', icon: 'lucide:clipboard-list' }, |
| | | { key: 'return-issue', label: '退料', icon: 'lucide:rotate-ccw' }, |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['srm:supplier-apply:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['system:login-log:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['system:mail-log:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['system:notify-message:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['system:operate-log:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['system:sms-log:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | icon: ACTION_ICON.VIEW, |
| | | auth: ['system:social-user:query'], |
| | | onClick: handleDetail.bind(null, row), |
| | | }, |
| | | ]" |
| | |
| | | { |
| | | label: $t('common.detail'), |
| | | type: 'link', |
| | | auth: ['mes:wm-barcode:query'], |
| | | onClick: handleView.bind(null, row), |
| | | }, |
| | | { |
| | |
| | | <div>物料编码:{{ selectedItem.itemCode || '-' }}</div> |
| | | <div>物料名称:{{ selectedItem.itemName || '-' }}</div> |
| | | <div>生产批号:{{ selectedItem.lotNumber || '-' }}</div> |
| | | <div>盘号:{{ selectedItem.reelNo || '-' }}</div> |
| | | </div> |
| | | </template> |
| | | <Input |
| | |
| | | width: 150, |
| | | }, |
| | | { |
| | | field: 'reelNo', |
| | | title: '盘号', |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | title: '物料编码', |
| | | width: 150, |
| | |
| | | label: '批次编号', |
| | | }, |
| | | { |
| | | field: 'reelNo', |
| | | label: '盘号', |
| | | }, |
| | | { |
| | | field: 'itemCode', |
| | | label: '物料编码', |
| | | }, |
| | |
| | | import { getItem } from '#/api/mdm/item'; |
| | | import { MdmItemSelect } from '#/views/basicData/mdm/components'; |
| | | import { SrmSupplierSelect } from '#/views/srm/supplier/components'; |
| | | import { WmBatchSelect } from '#/views/wls/batch/components'; |
| | | import BatchConfigDisplay from './batch-config-display.vue'; |
| | | import { |
| | | WmWarehouseAreaSelect, |
| | |
| | | const batchEnabled = ref(false); |
| | | // 是否手动填写批次号 |
| | | const manualBatchEntry = ref(false); |
| | | const hasExistingBatch = ref(false); |
| | | // 批次配置展示组件引用 |
| | | const batchConfigDisplayRef = ref<InstanceType<typeof BatchConfigDisplay>>(); |
| | | |
| | |
| | | } |
| | | |
| | | const item = selectedItem.value; |
| | | const isIn = operateType.value === 1; |
| | | const isIn = operateType.value === 1 && !hasExistingBatch.value; |
| | | |
| | | formApi.updateSchema([ |
| | | { fieldName: 'batchCode', dependencies: { show: () => manualBatchEntry.value } }, |
| | |
| | | |
| | | /** 物料选择变化 */ |
| | | async function handleItemChange(item: MdmItemApi.Item | undefined) { |
| | | hasExistingBatch.value = false; |
| | | selectedItem.value = item || null; |
| | | if (item?.id) { |
| | | const itemDetail = await getItem(item.id); |
| | |
| | | } |
| | | // 清空批次相关值 |
| | | await formApi.setFieldValue('batchCode', undefined); |
| | | await formApi.setFieldValue('batchId', undefined); |
| | | await formApi.setFieldValue('produceDate', undefined); |
| | | await formApi.setFieldValue('expireDate', undefined); |
| | | await formApi.setFieldValue('manualBatchEntry', false); |
| | |
| | | onChange: handleItemChange, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'batchId', |
| | | label: '已有批次/盘号', |
| | | component: markRaw(WmBatchSelect), |
| | | componentProps: { placeholder: '可选择已有追溯批次', disabled: true }, |
| | | dependencies: { |
| | | triggerFields: ['itemId'], |
| | | componentProps: (values: any) => ({ |
| | | itemId: values.itemId, |
| | | disabled: !values.itemId, |
| | | placeholder: '可选择已有追溯批次', |
| | | onChange: async (batch: any) => { |
| | | hasExistingBatch.value = !!batch?.id; |
| | | await updateBatchFields(); |
| | | }, |
| | | }), |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'warehouseId', |
| | |
| | | selectedWarehouse.value = null; |
| | | selectedLocation.value = null; |
| | | batchEnabled.value = false; |
| | | hasExistingBatch.value = false; |
| | | operateType.value = 1; |
| | | modalTitle.value = '库存调整'; |
| | | return; |
| | |
| | | const values = await formApi.getValues(); |
| | | |
| | | // 启用批次管理时的校验 |
| | | if (batchEnabled.value) { |
| | | if (batchEnabled.value && !values.batchId) { |
| | | if (manualBatchEntry.value && !values.batchCode) { |
| | | message.error('请输入批次号'); |
| | | return; |
| | |
| | | warehouseId: values.warehouseId, |
| | | locationId: values.locationId, |
| | | areaId: values.areaId, |
| | | batchId: values.batchId, |
| | | batchCode: values.batchCode, |
| | | produceDate: values.produceDate, |
| | | expireDate: values.expireDate, |
| | |
| | | warehouseId: values.warehouseId, |
| | | locationId: values.locationId, |
| | | areaId: values.areaId, |
| | | batchId: values.batchId, |
| | | batchCode: values.batchCode, |
| | | vendorId: values.vendorId, |
| | | quantity: values.quantity, |
| | |
| | | width: 100, |
| | | }, |
| | | { |
| | | field: 'reelNo', |
| | | title: '销售盘号', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'batchCode', |
| | | title: '批次号', |
| | | minWidth: 120, |
| | |
| | | ): VxeTableGridOptions<MesWmProductSalesDetailApi.ProductSalesDetail>['columns'] { |
| | | return [ |
| | | { |
| | | field: 'reelNo', |
| | | title: '拣货盘号', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'warehouseName', |
| | | title: '仓库名称', |
| | | minWidth: 100, |
| | |
| | | title: '批次号', |
| | | minWidth: 120, |
| | | }, |
| | | { field: 'reelNo', title: '盘号', minWidth: 120 }, |
| | | { |
| | | field: 'rqcCheckFlag', |
| | | title: '是否需要质检', |
| | |
| | | componentProps: hasItems |
| | | ? { |
| | | placeholder: '请选择物料', |
| | | options: items.map((item) => ({ |
| | | options: items.filter((item, index) => items.findIndex((other) => other.productId === item.productId) === index).map((item) => ({ |
| | | label: `${item.productName || ''}(${item.productBarCode || ''})`, |
| | | value: item.productId, |
| | | })), |
| | | showSearch: true, |
| | | onChange: (value: number | undefined) => { |
| | | const selected = items.find((i) => i.productId === value); |
| | | const matches = items.filter((i) => i.productId === value); |
| | | const selected = matches.length === 1 ? matches[0] : undefined; |
| | | onItemChange?.(selected); |
| | | }, |
| | | } |
| | |
| | | dependencies: { |
| | | triggerFields: ['itemId'], |
| | | componentProps: (values) => { |
| | | const selected = items?.find((i) => i.productId === values.itemId); |
| | | const matches = items?.filter((i) => i.productId === values.itemId) ?? []; |
| | | const selected = matches.length === 1 ? matches[0] : undefined; |
| | | return { |
| | | class: '!w-full', |
| | | max: selected?.count ?? undefined, |
| | |
| | | }; |
| | | }, |
| | | rules: (values) => { |
| | | const selected = items?.find((i) => i.productId === values.itemId); |
| | | const matches = items?.filter((i) => i.productId === values.itemId) ?? []; |
| | | const selected = matches.length === 1 ? matches[0] : undefined; |
| | | const max = selected?.count; |
| | | if (max !== undefined && max !== null) { |
| | | return z |
| | |
| | | component: markRaw(WmBatchSelect), |
| | | componentProps: { |
| | | clientId, |
| | | disabled: true, |
| | | disabled: false, |
| | | placeholder: '请选择批次', |
| | | salesOrderCode, |
| | | }, |
| | |
| | | triggerFields: ['itemId'], |
| | | componentProps: (values) => ({ |
| | | clientId, |
| | | disabled: true, |
| | | disabled: !values.itemId, |
| | | itemId: values.itemId, |
| | | placeholder: '请选择批次', |
| | | salesOrderCode, |
| | |
| | | stockable: boolean, |
| | | ): VxeTableGridOptions<MesWmReturnSalesDetailApi.ReturnSalesDetail>['columns'] { |
| | | return [ |
| | | { field: 'reelNo', title: '盘号', minWidth: 120 }, |
| | | { |
| | | field: 'batchCode', |
| | | title: '批次号', |
| | |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | saleOrderItems.value = []; |
| | | originalSnapshot.value = ''; |
| | | return; |
| | | } |
| | |
| | | if (list?.length) { |
| | | const orderId = list[0].id as number; |
| | | (formData.value as Record<string, unknown>).saleOrderId = orderId; |
| | | const order = await getSaleOrder(orderId); |
| | | saleOrderItems.value = order?.items || []; |
| | | } |
| | | } |
| | | if (formData.value?.saleOrderId) { |
| | | const order = await getSaleOrder(formData.value.saleOrderId); |
| | | saleOrderItems.value = order?.items || []; |
| | | } |
| | | // 设置到 values |
| | | await formApi.setValues(formData.value); |
| | | } finally { |
| | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { getBatchPage } from '#/api/mes/wm/batch'; |
| | | import { |
| | | createReturnSalesLine, |
| | | getReturnSalesLine, |
| | |
| | | maxQuantity.value = item?.count; |
| | | // 重置批次 |
| | | await formApi.setFieldValue('batchId', undefined); |
| | | if (item?.batchCode) { |
| | | try { |
| | | const batchPage = await getBatchPage({ |
| | | code: item.batchCode, |
| | | pageNo: 1, |
| | | pageSize: 1, |
| | | }); |
| | | const batchList = batchPage?.list; |
| | | if (batchList?.length) { |
| | | await formApi.setFieldValue('batchId', batchList[0].id); |
| | | } |
| | | } catch { |
| | | // 查询失败时忽略 |
| | | } |
| | | } |
| | | }, |
| | | ), |
| | | }); |
| | |
| | | }, |
| | | }, |
| | | { |
| | | field: 'reelNo', |
| | | title: '盘号', |
| | | minWidth: 120, |
| | | }, |
| | | { |
| | | field: 'batchCode', |
| | | title: '批次号', |
| | | minWidth: 120, |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesWmSalesNoticeLineApi } from '#/api/mes/wm/salesnotice/line'; |
| | | import type { ErpSaleOrderApi } from '#/api/erp/sale/order'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | import { message, Select } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { getSaleOrderItemListByOrderId } from '#/api/erp/sale/order'; |
| | | import { getSalesNotice } from '#/api/mes/wm/salesnotice'; |
| | | import { |
| | | createSalesNoticeLine, |
| | | getSalesNoticeLine, |
| | |
| | | const emit = defineEmits(['success']); |
| | | const formData = ref<MesWmSalesNoticeLineApi.SalesNoticeLine>(); |
| | | const noticeId = ref<number>(); // 所属通知单编号 |
| | | const saleOrderId = ref<number>(); |
| | | const saleOrderItemId = ref<number>(); |
| | | const saleItems = ref<ErpSaleOrderApi.SaleOrderItem[]>([]); |
| | | const saleItemOptions = computed(() => saleItems.value.map((item) => ({ |
| | | value: item.id, |
| | | label: `${item.productName || item.productId || '-'} / 盘号:${item.reelNo || '未填写'} / 明细:${item.id}`, |
| | | }))); |
| | | |
| | | async function handleSaleItemChange(id: number) { |
| | | const item = saleItems.value.find((entry) => entry.id === id); |
| | | if (item?.productId) await formApi.setFieldValue('itemId', item.productId); |
| | | } |
| | | |
| | | const getTitle = computed(() => { |
| | | return formData.value?.id |
| | |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (saleOrderId.value && !saleOrderItemId.value) { |
| | | message.warning('请选择销售订单明细'); |
| | | return; |
| | | } |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | |
| | | const data = |
| | | (await formApi.getValues()) as MesWmSalesNoticeLineApi.SalesNoticeLine; |
| | | data.noticeId = noticeId.value; |
| | | data.saleOrderItemId = saleOrderItemId.value; |
| | | try { |
| | | await (formData.value?.id |
| | | ? updateSalesNoticeLine({ ...data, id: formData.value.id }) |
| | |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | formData.value = undefined; |
| | | saleOrderId.value = undefined; |
| | | saleOrderItemId.value = undefined; |
| | | saleItems.value = []; |
| | | return; |
| | | } |
| | | // 加载数据 |
| | | const data = modalApi.getData<{ id?: number; noticeId: number }>(); |
| | | noticeId.value = data.noticeId; |
| | | if (!data.id) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | formData.value = await getSalesNoticeLine(data.id); |
| | | // 设置到 values |
| | | await formApi.setValues(formData.value); |
| | | const notice = await getSalesNotice(data.noticeId); |
| | | saleOrderId.value = notice.saleOrderId; |
| | | if (notice.saleOrderId) { |
| | | saleItems.value = await getSaleOrderItemListByOrderId(notice.saleOrderId); |
| | | } |
| | | if (data.id) { |
| | | formData.value = await getSalesNoticeLine(data.id); |
| | | saleOrderItemId.value = formData.value.saleOrderItemId; |
| | | await formApi.setValues(formData.value); |
| | | } |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-3/5"> |
| | | <div v-if="saleOrderId" class="mx-4 mb-4 flex items-center gap-3"> |
| | | <span>销售明细</span> |
| | | <Select v-model:value="saleOrderItemId" class="flex-1" :options="saleItemOptions" |
| | | placeholder="请选择销售订单明细和盘号" @change="handleSaleItemChange" /> |
| | | </div> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | |
| | | title: '批次号', |
| | | minWidth: 120, |
| | | }, |
| | | { field: 'reelNo', title: '盘号', minWidth: 120 }, |
| | | { |
| | | field: 'fromWarehouseName', |
| | | title: '移出仓库', |