From fb4db4ae9b6a7f113ba049f6789e6916c0dcc276 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 12 十月 2026 09:15:08 +0800
Subject: [PATCH] feat(mes): 新增业务码支持并优化追溯查询功能

---
 src/views/wls/productsales/modules/form.vue |   62 +++++++++++++++++++++++--------
 1 files changed, 46 insertions(+), 16 deletions(-)

diff --git a/src/views/wls/productsales/modules/form.vue b/src/views/wls/productsales/modules/form.vue
index dcb1abc..27ee471 100644
--- a/src/views/wls/productsales/modules/form.vue
+++ b/src/views/wls/productsales/modules/form.vue
@@ -16,6 +16,7 @@
   createProductSales,
   finishProductSales,
   getProductSales,
+  previewProductSalesScan,
   scanProductSales,
   shippingProductSales,
   stockProductSales,
@@ -26,12 +27,15 @@
 
 import { useFormSchema } from '../data';
 import LineList from './line-list.vue';
+import PickingBags from './picking-bags.vue';
 
 const emit = defineEmits(['success']);
 const formType = ref<FormType>('create');
 const formData = ref<MesWmProductSalesApi.ProductSales>();
 const scanContent = ref('');
-const scanQuantity = ref<number>();
+const scanType = ref<'BAG' | 'PALLET' | 'BATCH'>('BAG');
+const scanPreview = ref<MesWmProductSalesApi.ProductSalesScanResponse>();
+const selectedBagIds = ref<number[]>([]);
 const scanLoading = ref(false);
 const scanRefreshKey = ref(0);
 const originalSnapshot = ref(''); // 琛ㄥ崟鍘熷鏁版嵁蹇収锛岀敤浜庢彁浜ゆ椂璺宠繃鏈彉鏇寸殑淇濆瓨璇锋眰
@@ -104,25 +108,45 @@
   }
 }
 
-/** 鎵爜鎷h揣锛氭壂鐮佹灙閫氬父浠ュ洖杞︾粨鏉熻緭鍏� */
+/** 鍏堣瘑鍒璞″苟閫夋嫨琚嬬爜锛屽洖杞︿笉浼氱洿鎺ュ啓鍏ユ嫞璐с�� */
 async function handleScan() {
   if (!formData.value?.id || !scanContent.value.trim() || scanLoading.value) {
     return;
   }
   scanLoading.value = true;
   try {
+    scanPreview.value = undefined;
+    selectedBagIds.value = [];
+    const result = await previewProductSalesScan(scanContent.value.trim(), scanType.value, formData.value.id);
+    scanPreview.value = result;
+    if (result.scanType === 'BAG') selectedBagIds.value = result.bags?.filter(b => b.selectable).map(b => b.id) || [];
+    if (!result.scanQuantity) message.warning('褰撳墠瀵硅薄娌℃湁鍙嫞琚嬬爜锛岃鏍稿璐ㄦ鍜屽簱瀛樼姸鎬�');
+  } finally { scanLoading.value = false; }
+}
+
+async function confirmScan() {
+  if (!formData.value?.id || !scanPreview.value || !selectedBagIds.value.length || scanLoading.value) return;
+  const source = scanPreview.value;
+  const bagIds = [...selectedBagIds.value];
+  scanLoading.value = true;
+  try { await confirm(`纭灏嗘墍閫� ${bagIds.length} 琚嬪姞鍏ユ嫞璐у苟鍏宠仈杩芥函琚嬬爜锛焋); }
+  catch { scanLoading.value = false; return; }
+  try {
     const result = await scanProductSales({
-      quantity: scanQuantity.value,
+      quantity: bagIds.length,
       salesId: formData.value.id,
-      scanContent: scanContent.value.trim(),
+      scanContent: source.scanContent!,
+      scanType: source.scanType as 'BAG' | 'PALLET' | 'BATCH',
+      bagIds,
     });
     message[result.alreadyScanned ? 'warning' : 'success'](
       result.alreadyScanned
         ? `璇ョ爜宸叉壂鎻忥紝鏄庣粏缂栧彿锛�${result.detailId ?? '-'}`
-        : `${result.message || '鎵爜鎴愬姛'}${result.scanType ? `锛�${result.scanType === 'PALLET' ? '鎵樼洏鐮�' : '琚嬬爜'}锛塦 : ''}`,
+        : `宸插姞鍏ユ嫞璐� ${result.outboundQuantity} 琚嬶紝閫愯鍏宠仈杩芥函鐮乣,
     );
     scanContent.value = '';
-    scanQuantity.value = undefined;
+    scanPreview.value = undefined;
+    selectedBagIds.value = [];
     scanRefreshKey.value += 1;
   } finally {
     scanLoading.value = false;
@@ -228,6 +252,9 @@
     }
   },
   async onOpenChange(isOpen: boolean) {
+    scanPreview.value = undefined;
+    selectedBagIds.value = [];
+    scanContent.value = '';
     if (!isOpen) {
       formData.value = undefined;
       originalSnapshot.value = '';
@@ -262,25 +289,28 @@
       <Divider>鐗╂枡淇℃伅</Divider>
       <div class="mx-4">
         <div v-if="isStock" class="mb-3 flex items-center gap-2 px-4">
+          <label for="sales-picking-type" class="sr-only">鎷h揣鎵爜绫诲瀷</label>
+          <a-select id="sales-picking-type" v-model:value="scanType" :disabled="scanLoading" style="width:140px" @change="scanPreview = undefined; selectedBagIds = []">
+            <a-select-option value="BAG">琚嬬爜</a-select-option><a-select-option value="PALLET">鎵樼洏鐮�</a-select-option><a-select-option value="BATCH">鐢熶骇鎵规鐮�</a-select-option>
+          </a-select>
           <a-input
             v-model:value="scanContent"
             :disabled="scanLoading"
             autofocus
             class="flex-1"
-            placeholder="璇锋壂鎻忚鐮佹垨鎵樼洏鐮侊紝鍥炶溅鎻愪氦"
+            placeholder="鎵弿鎵�閫夌被鍨嬬爜锛屽洖杞﹁瘑鍒�"
             @press-enter="handleScan"
           />
-          <a-input-number
-            v-model:value="scanQuantity"
-            :disabled="scanLoading"
-            :min="0"
-            placeholder="鏁伴噺锛堝彲閫夛級"
-            style="width: 140px"
-          />
           <Button :loading="scanLoading" type="default" @click="handleScan">
-            鎵爜
+            璇嗗埆鐮佸��
           </Button>
         </div>
+        <section v-if="isStock && scanPreview" class="mb-4 rounded-lg border border-border p-4">
+          <h3 class="font-semibold">鏍稿鎷h揣瀵硅薄</h3><p>鎵规 {{scanPreview.batchCode}} 路 鍙嫞 {{scanPreview.scanQuantity}} 琚�</p>
+          <PickingBags v-if="scanPreview.scanType !== 'BAG'" v-model="selectedBagIds" :bags="scanPreview.bags || []" :disabled="scanLoading" />
+          <p v-else>琚嬬爜 {{scanPreview.bags?.[0]?.code}} 路 鏈 {{selectedBagIds.length}} 琚�</p>
+          <div class="mt-3 flex gap-2"><Button type="primary" :loading="scanLoading" :disabled="!selectedBagIds.length" @click="confirmScan">纭鍔犲叆鎷h揣</Button><Button :disabled="scanLoading" @click="scanPreview = undefined">鍙栨秷鏈鎵爜</Button></div>
+        </section>
         <LineList
           :form-type="formType"
           :notice-id="formData.noticeId"
@@ -298,7 +328,7 @@
         >
           <Button type="primary">鎻愪氦</Button>
         </Popconfirm>
-        <Button v-if="isStock" type="primary" @click="handleStock">
+        <Button v-if="isStock" type="primary" :disabled="scanLoading || !!scanPreview" @click="handleStock">
           鎵ц鎷h揣
         </Button>
         <Popconfirm

--
Gitblit v1.9.3