From d5048a33e4760d414115a5e25645d30b41d24198 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期六, 29 八月 2026 18:06:07 +0800
Subject: [PATCH] fix(wls): 修复多个组件中的类型安全和数据验证问题

---
 src/views/wls/itemreceipt/modules/an-select-dialog.vue        |    2 
 src/views/mes/pro/feedback/modules/batch-feedback.vue         |   45 ++++++++++-
 src/views/wls/materialstock/components/stock-adjust-modal.vue |   56 +++++++------
 src/views/wls/returnsales/modules/form.vue                    |   17 ++-
 src/views/wls/approval/config/index.vue                       |    4 
 src/views/wls/productreceipt/modules/line-list.vue            |   16 ++++
 src/views/wls/returnsales/modules/line-form.vue               |    6 
 src/views/wls/productsales/data.ts                            |    2 
 src/views/wls/approval/config/modules/process-config-form.vue |   14 +-
 src/views/wls/arrivalnotice/modules/po-select-dialog.vue      |    2 
 src/views/wls/approval/config/data.ts                         |   21 +++--
 11 files changed, 122 insertions(+), 63 deletions(-)

diff --git a/src/views/mes/pro/feedback/modules/batch-feedback.vue b/src/views/mes/pro/feedback/modules/batch-feedback.vue
index 7458c64..2f38bcb 100644
--- a/src/views/mes/pro/feedback/modules/batch-feedback.vue
+++ b/src/views/mes/pro/feedback/modules/batch-feedback.vue
@@ -1,13 +1,14 @@
 <script lang="ts" setup>
 import type { MesProTaskApi } from '#/api/mes/pro/task';
 
-import { ref } from 'vue';
+import { computed, ref } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
 import { Button, message, Tag } from 'ant-design-vue';
 
 import { batchCreateFeedback } from '#/api/mes/pro/feedback';
+import { getRouteProcessByRouteAndProcess } from '#/api/mes/pro/route/process';
 import ProTaskSelectDialog from '#/views/mes/pro/task/components/select-dialog.vue';
 
 defineOptions({ name: 'BatchFeedbackForm' });
@@ -32,22 +33,49 @@
 
 const taskDialogRef = ref<InstanceType<typeof ProTaskSelectDialog>>();
 const selectedTasks = ref<MesProTaskApi.Task[]>([]);
+const needReportQuantityMap = ref<Record<number, boolean>>({});
 const formData = ref({
   feedbackQuantity: undefined as number | undefined,
   remark: '',
 });
 const submitting = ref(false);
 
+/** 鏄惁闇�瑕佸~鍐欐姤宸ユ暟閲忥紙浠讳竴閫変腑浠诲姟宸ュ簭瑕佹眰濉啓鏁伴噺鍗冲繀濉級 */
+const needQuantity = computed(() =>
+  selectedTasks.value.some(
+    (t) => needReportQuantityMap.value[t.id!] ?? true,
+  ),
+);
+
 function handleOpenTaskDialog() {
   taskDialogRef.value?.open([], { multiple: true });
 }
 
-function handleTaskSelected(rows: MesProTaskApi.Task[]) {
+/** 鎸夐�変腑浠诲姟宸ュ簭鍔犺浇鏄惁闇�瑕佹姤宸ユ暟閲� */
+async function handleTaskSelected(rows: MesProTaskApi.Task[]) {
   selectedTasks.value = rows;
+  needReportQuantityMap.value = {};
+  for (const task of rows) {
+    if (!task.routeId || !task.processId) {
+      continue;
+    }
+    try {
+      const routeProcess = await getRouteProcessByRouteAndProcess(
+        task.routeId,
+        task.processId,
+      );
+      needReportQuantityMap.value[task.id!] =
+        routeProcess?.needReportQuantity ?? true;
+    } catch {
+      // 鍔犺浇澶辫触鎸夐粯璁ゅ鐞嗭紙鏁伴噺蹇呭~锛�
+      needReportQuantityMap.value[task.id!] = true;
+    }
+  }
 }
 
 function handleRemoveTask(taskId: number) {
   selectedTasks.value = selectedTasks.value.filter((t) => t.id !== taskId);
+  delete needReportQuantityMap.value[taskId];
 }
 
 async function handleSubmit() {
@@ -55,7 +83,7 @@
     message.warning('璇烽�夋嫨浠诲姟');
     return;
   }
-  if (!formData.value.feedbackQuantity) {
+  if (needQuantity.value && !formData.value.feedbackQuantity) {
     message.warning('璇疯緭鍏ユ姤宸ユ暟閲�');
     return;
   }
@@ -63,7 +91,9 @@
   try {
     const result = await batchCreateFeedback({
       taskIds: selectedTasks.value.map((t) => t.id!),
-      feedbackQuantity: formData.value.feedbackQuantity,
+      feedbackQuantity: needQuantity.value
+        ? (formData.value.feedbackQuantity ?? 0)
+        : 0,
       remark: formData.value.remark || undefined,
     });
     if (result.failCount) {
@@ -101,7 +131,12 @@
           </Tag>
         </div>
       </a-form-item>
-      <a-form-item label="鎶ュ伐鏁伴噺" required>
+      <a-form-item
+        v-if="needQuantity"
+        label="鎶ュ伐鏁伴噺"
+        required
+        tooltip="宸ュ簭閰嶇疆涓轰笉闇�濉啓鎶ュ伐鏁伴噺鏃讹紝鍚堟牸鍝�/涓嶈壇鍝佹暟閲忕敱璐ㄦ纭畾"
+      >
         <a-input-number
           v-model:value="formData.feedbackQuantity"
           :min="0.01"
diff --git a/src/views/wls/approval/config/data.ts b/src/views/wls/approval/config/data.ts
index 49ecc5b..c154f1f 100644
--- a/src/views/wls/approval/config/data.ts
+++ b/src/views/wls/approval/config/data.ts
@@ -62,8 +62,8 @@
             checked: config?.approvalEnabled ?? false,
             checkedChildren: '寮�',
             unCheckedChildren: '鍏�',
-            onChange: (checked: boolean) => {
-              handleChange(row, 'INBOUND', checked);
+            onChange: (checked) => {
+              handleChange(row, 'INBOUND', Boolean(checked));
             },
           });
         },
@@ -82,8 +82,8 @@
             checked: config?.approvalEnabled ?? false,
             checkedChildren: '寮�',
             unCheckedChildren: '鍏�',
-            onChange: (checked: boolean) => {
-              handleChange(row, 'OUTBOUND', checked);
+            onChange: (checked) => {
+              handleChange(row, 'OUTBOUND', Boolean(checked));
             },
           });
         },
@@ -102,8 +102,8 @@
             checked: config?.approvalEnabled ?? false,
             checkedChildren: '寮�',
             unCheckedChildren: '鍏�',
-            onChange: (checked: boolean) => {
-              handleChange(row, 'TRANSFER', checked);
+            onChange: (checked) => {
+              handleChange(row, 'TRANSFER', Boolean(checked));
             },
           });
         },
@@ -122,8 +122,8 @@
             checked: config?.approvalEnabled ?? false,
             checkedChildren: '寮�',
             unCheckedChildren: '鍏�',
-            onChange: (checked: boolean) => {
-              handleChange(row, 'CHECK', checked);
+            onChange: (checked) => {
+              handleChange(row, 'CHECK', Boolean(checked));
             },
           });
         },
@@ -173,7 +173,9 @@
 }
 
 /** 娴佺▼閰嶇疆琛ㄥ崟 */
-export function useProcessFormSchema(): VbenFormSchema[] {
+export function useProcessFormSchema(
+  onBizTypeChange?: (value?: string) => void,
+): VbenFormSchema[] {
   return [
     {
       fieldName: 'warehouseId',
@@ -190,6 +192,7 @@
       componentProps: {
         options: BIZ_TYPE_OPTIONS,
         placeholder: '璇烽�夋嫨涓氬姟绫诲瀷',
+        onChange: onBizTypeChange,
       },
       rules: 'required',
     },
diff --git a/src/views/wls/approval/config/index.vue b/src/views/wls/approval/config/index.vue
index 5f92252..3a5e5ac 100644
--- a/src/views/wls/approval/config/index.vue
+++ b/src/views/wls/approval/config/index.vue
@@ -2,7 +2,7 @@
 import type { VxeTableGridOptions } from '#/adapter/vxe-table';
 import type { WmsApprovalApi } from '#/api/mes/wm/approval';
 
-import { ref } from 'vue';
+import { ref, unref } from 'vue';
 
 import { Page, useVbenModal } from '@vben/common-ui';
 
@@ -69,7 +69,7 @@
     columns: useGridColumns(handleApprovalChange),
     height: 'auto',
     keepSource: true,
-    data: warehouseConfigList,
+    data: unref(warehouseConfigList),
     proxyConfig: {
       ajax: {
         query: async ({ page }, formValues) => {
diff --git a/src/views/wls/approval/config/modules/process-config-form.vue b/src/views/wls/approval/config/modules/process-config-form.vue
index c6f24ab..18d00c8 100644
--- a/src/views/wls/approval/config/modules/process-config-form.vue
+++ b/src/views/wls/approval/config/modules/process-config-form.vue
@@ -1,7 +1,7 @@
 <script lang="ts" setup>
 import type { WmsApprovalApi } from '#/api/mes/wm/approval';
 
-import { computed, ref, watch } from 'vue';
+import { ref, watch } from 'vue';
 
 import { useVbenModal } from '@vben/common-ui';
 
@@ -25,7 +25,9 @@
     },
   },
   layout: 'horizontal',
-  schema: useProcessFormSchema(),
+  schema: useProcessFormSchema((value) => {
+    currentBizType.value = value;
+  }),
   showDefaultActions: false,
 });
 
@@ -53,6 +55,7 @@
   },
   onOpenChange(isOpen) {
     if (isOpen) {
+      currentBizType.value = undefined;
       const data = modalApi.getData() as {
         warehouseId: number;
         warehouseName: string;
@@ -69,11 +72,8 @@
   },
 });
 
-/** 褰撳墠閫変腑鐨勪笟鍔$被鍨� */
-const currentBizType = computed(() => {
-  const values = formApi.getValues();
-  return values.bizType;
-});
+/** 褰撳墠閫変腑鐨勪笟鍔$被鍨嬶紙formApi.getValues 涓哄紓姝ワ紝鏀圭敱瀛楁 onChange 鍚屾锛� */
+const currentBizType = ref<string>();
 
 /** 鐩戝惉涓氬姟绫诲瀷鍙樺寲锛屽姞杞藉搴旂殑娴佺▼鍒楄〃 */
 watch(currentBizType, async (bizType) => {
diff --git a/src/views/wls/arrivalnotice/modules/po-select-dialog.vue b/src/views/wls/arrivalnotice/modules/po-select-dialog.vue
index 4dd38ed..9dcafdf 100644
--- a/src/views/wls/arrivalnotice/modules/po-select-dialog.vue
+++ b/src/views/wls/arrivalnotice/modules/po-select-dialog.vue
@@ -105,7 +105,7 @@
       message.warning('璇烽�夋嫨閲囪喘璁㈠崟');
       return;
     }
-    emit('selected', selectedRows.id);
+    emit('selected', selectedRows.id!);
     await modalApi.close();
   },
   async onOpened() {
diff --git a/src/views/wls/itemreceipt/modules/an-select-dialog.vue b/src/views/wls/itemreceipt/modules/an-select-dialog.vue
index eef4eef..9744f32 100644
--- a/src/views/wls/itemreceipt/modules/an-select-dialog.vue
+++ b/src/views/wls/itemreceipt/modules/an-select-dialog.vue
@@ -111,7 +111,7 @@
       message.warning('璇烽�夋嫨鍒拌揣閫氱煡鍗�');
       return;
     }
-    emit('selected', selectedRows.id);
+    emit('selected', selectedRows.id!);
     await modalApi.close();
   },
   async onOpenChange(isOpen: boolean) {
diff --git a/src/views/wls/materialstock/components/stock-adjust-modal.vue b/src/views/wls/materialstock/components/stock-adjust-modal.vue
index 3028b7d..2fec79f 100644
--- a/src/views/wls/materialstock/components/stock-adjust-modal.vue
+++ b/src/views/wls/materialstock/components/stock-adjust-modal.vue
@@ -55,15 +55,15 @@
 
   if (!enabled) {
     formApi.updateSchema([
-      { fieldName: 'batchCode', dependencies: { show: () => false } },
-      { fieldName: 'manualBatchEntry', dependencies: { show: () => false } },
-      { fieldName: 'produceDate', dependencies: { show: () => false } },
-      { fieldName: 'expireDate', dependencies: { show: () => false } },
-      { fieldName: 'receiptDate', dependencies: { show: () => false } },
-      { fieldName: 'vendorId', dependencies: { show: () => true } },
-      { fieldName: 'purchaseOrderCode', dependencies: { show: () => false } },
-      { fieldName: 'lotNumber', dependencies: { show: () => false } },
-      { fieldName: 'qualityStatus', dependencies: { show: () => false } },
+      { fieldName: 'batchCode', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'manualBatchEntry', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'produceDate', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'expireDate', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'receiptDate', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'vendorId', dependencies: { show: () => true, triggerFields: [''] } },
+      { fieldName: 'purchaseOrderCode', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'lotNumber', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'qualityStatus', dependencies: { show: () => false, triggerFields: [''] } },
     ]);
     return;
   }
@@ -72,15 +72,15 @@
   const isIn = operateType.value === 1;
 
   formApi.updateSchema([
-    { fieldName: 'batchCode', dependencies: { show: () => manualBatchEntry.value } },
-    { fieldName: 'manualBatchEntry', dependencies: { show: () => true } },
-    { fieldName: 'produceDate', dependencies: { show: () => isIn && !!item?.produceDateFlag } },
-    { fieldName: 'expireDate', dependencies: { show: () => isIn && !!item?.expireDateFlag } },
-    { fieldName: 'receiptDate', dependencies: { show: () => isIn && !!item?.receiptDateFlag } },
-    { fieldName: 'vendorId', dependencies: { show: () => !isIn || !!item?.vendorFlag } },
-    { fieldName: 'purchaseOrderCode', dependencies: { show: () => isIn && !!item?.purchaseOrderCodeFlag } },
-    { fieldName: 'lotNumber', dependencies: { show: () => isIn && !!item?.lotNumberFlag } },
-    { fieldName: 'qualityStatus', dependencies: { show: () => isIn && !!item?.qualityStatusFlag } },
+    { fieldName: 'batchCode', dependencies: { show: () => manualBatchEntry.value, triggerFields: [''] } },
+    { fieldName: 'manualBatchEntry', dependencies: { show: () => true, triggerFields: [''] } },
+    { fieldName: 'produceDate', dependencies: { show: () => isIn && !!item?.produceDateFlag, triggerFields: [''] } },
+    { fieldName: 'expireDate', dependencies: { show: () => isIn && !!item?.expireDateFlag, triggerFields: [''] } },
+    { fieldName: 'receiptDate', dependencies: { show: () => isIn && !!item?.receiptDateFlag, triggerFields: [''] } },
+    { fieldName: 'vendorId', dependencies: { show: () => !isIn || !!item?.vendorFlag, triggerFields: [''] } },
+    { fieldName: 'purchaseOrderCode', dependencies: { show: () => isIn && !!item?.purchaseOrderCodeFlag, triggerFields: [''] } },
+    { fieldName: 'lotNumber', dependencies: { show: () => isIn && !!item?.lotNumberFlag, triggerFields: [''] } },
+    { fieldName: 'qualityStatus', dependencies: { show: () => isIn && !!item?.qualityStatusFlag, triggerFields: [''] } },
   ]);
 }
 
@@ -127,6 +127,7 @@
 async function handleOperateTypeChange(type: 1 | 2) {
   operateType.value = type;
   modalTitle.value = type === 1 ? '搴撳瓨鍏ュ簱' : '搴撳瓨鍑哄簱';
+  modalApi.setState({ title: modalTitle.value });
   await formApi.setFieldValue('operateType', type);
   // 鏇存柊鎵规瀛楁鏄剧ず
   await updateBatchFields();
@@ -403,20 +404,21 @@
       batchEnabled.value = false;
       operateType.value = 1;
       modalTitle.value = '搴撳瓨璋冩暣';
+      modalApi.setState({ title: modalTitle.value });
       return;
     }
     // 閲嶇疆琛ㄥ崟
     await formApi.resetForm();
     // 榛樿闅愯棌鎵规鐩稿叧瀛楁
     formApi.updateSchema([
-      { fieldName: 'batchCode', dependencies: { show: () => false } },
-      { fieldName: 'manualBatchEntry', dependencies: { show: () => false } },
-      { fieldName: 'produceDate', dependencies: { show: () => false } },
-      { fieldName: 'expireDate', dependencies: { show: () => false } },
-      { fieldName: 'receiptDate', dependencies: { show: () => false } },
-      { fieldName: 'purchaseOrderCode', dependencies: { show: () => false } },
-      { fieldName: 'lotNumber', dependencies: { show: () => false } },
-      { fieldName: 'qualityStatus', dependencies: { show: () => false } },
+      { fieldName: 'batchCode', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'manualBatchEntry', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'produceDate', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'expireDate', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'receiptDate', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'purchaseOrderCode', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'lotNumber', dependencies: { show: () => false, triggerFields: [''] } },
+      { fieldName: 'qualityStatus', dependencies: { show: () => false, triggerFields: [''] } },
     ]);
     // 閲嶇疆鎵嬪姩濉啓鎵规鍙风姸鎬�
     manualBatchEntry.value = false;
@@ -436,7 +438,7 @@
       }
     }
   },
-  title: modalTitle,
+  title: '搴撳瓨璋冩暣',
 });
 
 /** 鎻愪氦琛ㄥ崟 */
diff --git a/src/views/wls/productreceipt/modules/line-list.vue b/src/views/wls/productreceipt/modules/line-list.vue
index e28cdac..a68891c 100644
--- a/src/views/wls/productreceipt/modules/line-list.vue
+++ b/src/views/wls/productreceipt/modules/line-list.vue
@@ -153,6 +153,22 @@
           details = await getProductReceiptDetailListByLineId(line.id!);
           detailMap[line.id!] = details;
         }
+        // 鍕鹃�夊叆搴撶殑琛屽繀椤诲凡鏈変笂鏋舵槑缁嗭紝涓旀槑缁嗘暟閲忎箣鍜岀瓑浜庤鏀惰揣鏁伴噺
+        if (!details.length) {
+          message.error(`鐗╂枡銆�${line.itemName}銆嶅凡鍕鹃�夊叆搴擄紝璇峰厛娣诲姞涓婃灦鏄庣粏`);
+          return;
+        }
+        const lineQty = Number(line.quantity ?? 0);
+        const sumQty = details.reduce(
+          (acc, detail) => acc + Number(detail.quantity ?? 0),
+          0,
+        );
+        if (lineQty !== sumQty) {
+          message.error(
+            `鐗╂枡銆�${line.itemName}銆嶄笂鏋舵槑缁嗘暟閲忎箣鍜岋紙${sumQty}锛変笌鏀惰揣鏁伴噺锛�${lineQty}锛変笉涓�鑷碻,
+          );
+          return;
+        }
         row.details = details.map((detail) => ({
           warehouseId: detail.warehouseId!,
           locationId: detail.locationId!,
diff --git a/src/views/wls/productsales/data.ts b/src/views/wls/productsales/data.ts
index 9522d75..b9b0cdd 100644
--- a/src/views/wls/productsales/data.ts
+++ b/src/views/wls/productsales/data.ts
@@ -132,7 +132,7 @@
             contactAddress: notice?.recipientAddress,
             contactName: notice?.recipientName,
             contactTelephone: notice?.recipientTelephone,
-            salesOrderCode: notice?.salesOrderCode,
+            salesOrderCode: notice?.saleOrderCode,
           });
         },
         status: MesWmSalesNoticeStatusEnum.APPROVED,
diff --git a/src/views/wls/returnsales/modules/form.vue b/src/views/wls/returnsales/modules/form.vue
index 2f57364..e9cb5e2 100644
--- a/src/views/wls/returnsales/modules/form.vue
+++ b/src/views/wls/returnsales/modules/form.vue
@@ -191,16 +191,19 @@
       try {
         formData.value = await getReturnSales(data.id);
         // 閫氳繃閿�鍞鍗曞彿鍙嶆煡璁㈠崟ID锛岀‘淇� ErpSaleOrderSelect 鑳芥纭洖鏄�
-        if (formData.value?.salesOrderCode && !formData.value.saleOrderId) {
+        const formValues = formData.value as MesWmReturnSalesApi.ReturnSales & {
+          saleOrderId?: number;
+        };
+        if (formValues.salesOrderCode && !formValues.saleOrderId) {
           const orderPage = await getSaleOrderPage({
             pageNo: 1,
             pageSize: 1,
-            no: formData.value.salesOrderCode,
-          } as Record<string, unknown> as never);
-          const list = (orderPage as Record<string, unknown>)?.list as Array<Record<string, unknown>> | undefined;
-          if (list?.length) {
-            const orderId = list[0].id as number;
-            (formData.value as Record<string, unknown>).saleOrderId = orderId;
+            no: formValues.salesOrderCode,
+          } as never);
+          const first = orderPage?.list?.[0];
+          if (first) {
+            const orderId = Number(first.id);
+            formValues.saleOrderId = orderId;
             const order = await getSaleOrder(orderId);
             saleOrderItems.value = order?.items || [];
           }
diff --git a/src/views/wls/returnsales/modules/line-form.vue b/src/views/wls/returnsales/modules/line-form.vue
index 06adfaf..9021799 100644
--- a/src/views/wls/returnsales/modules/line-form.vue
+++ b/src/views/wls/returnsales/modules/line-form.vue
@@ -98,9 +98,9 @@
                 pageNo: 1,
                 pageSize: 1,
               });
-              const batchList = batchPage?.list;
-              if (batchList?.length) {
-                await formApi.setFieldValue('batchId', batchList[0].id);
+              const firstBatch = batchPage?.list?.[0];
+              if (firstBatch) {
+                await formApi.setFieldValue('batchId', firstBatch.id);
               }
             } catch {
               // 鏌ヨ澶辫触鏃跺拷鐣�

--
Gitblit v1.9.3