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/mes/pro/bagCode/index.vue |  123 ++++++++++++++++++++--------------------
 1 files changed, 61 insertions(+), 62 deletions(-)

diff --git a/src/views/mes/pro/bagCode/index.vue b/src/views/mes/pro/bagCode/index.vue
index 65ae024..cf22f99 100644
--- a/src/views/mes/pro/bagCode/index.vue
+++ b/src/views/mes/pro/bagCode/index.vue
@@ -6,17 +6,20 @@
   import { MesProBagCodeStatusEnum } from "@vben/constants";
   import { downloadFileFromBlobPart } from "@vben/utils";
 
-  import { message, Modal } from "ant-design-vue";
+  import { Button, message, Modal } from "ant-design-vue";
 
   import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table";
   import {
     deleteBagCodesByUuid,
     exportBagCodeExcel,
     exportBagQr,
+    exportBagBusinessQr,
+    generateBagBusinessCodes,
     getBagCodePage,
     bindBagCodeBatch,
     unbindBagCodePallet,
   } from "#/api/mes/pro/bagCode";
+  import { IconifyIcon } from "@vben/icons";
   import { $t } from "#/locales";
 
   import { useGridColumns, useGridFormSchema } from "./data";
@@ -26,6 +29,7 @@
   import RawGenerateModal from "./modules/raw-generate-form.vue";
   import ReplaceModal from "./modules/replace-form.vue";
   import QrTraceModal from "../components/qr-trace-modal.vue";
+  import BusinessQrModal from "../components/business-qr.vue";
 
   defineOptions({ name: "MesProBagCode" });
 
@@ -59,6 +63,29 @@
     destroyOnClose: true,
   });
 
+  const [BusinessQrViewModal, businessQrApi] = useVbenModal({
+    connectedComponent: BusinessQrModal, destroyOnClose: true,
+  });
+
+  function handleBusinessQr(row: MesProBagCodeApi.BagCode) {
+    if (!row.businessCode) { message.warning('璇峰厛琛ョ敓鎴愪笟鍔$爜'); return; }
+    businessQrApi.setData({ code: row.businessCode }).open();
+  }
+
+  async function handleGenerateBusinessCodes() {
+    const records = getSelectedRecords();
+    if (!records) return;
+    if (records.length > 200) { message.warning('鍗曟鏈�澶氳ˉ鐢熸垚 200 鏉�'); return; }
+    if (records.some(row => row.status === MesProBagCodeStatusEnum.CANCELED)) {
+      message.warning('宸蹭綔搴熻鐮佷笉鍙ˉ鐢熸垚涓氬姟鐮�'); return;
+    }
+    const ids = records.map(row => row.id).filter((id): id is number => id != null);
+    if (ids.length !== records.length) { message.warning('鎵�閫夎鐮佺己灏戠紪鍙�'); return; }
+    const count = await generateBagBusinessCodes(ids);
+    message.success(`宸茶ˉ鐢熸垚 ${count} 浠戒笟鍔$爜锛屽凡鏈夌爜鍊间繚鎸佷笉鍙榒);
+    handleRefresh();
+  }
+
   /** 鍒锋柊琛ㄦ牸 */
   function handleRefresh() {
     gridApi.query();
@@ -91,7 +118,7 @@
   }
 
   /** 瀵煎嚭浜岀淮鐮� ZIP锛堟寜褰撳墠鏌ヨ鏉′欢鐨勭敓鎴愮粍/鎵规锛� */
-  async function handleExportQr() {
+  async function handleExportQr(kind: 'trace' | 'business' = 'trace') {
     const values = await gridApi.formApi.getValues();
     const params: { uuid?: string; batchId?: number } = {};
     if (values.uuid) {
@@ -104,8 +131,8 @@
       message.warning("璇峰厛鎸夌敓鎴愮粍鎴栨壒娆$瓫閫夊悗鍐嶅鍑轰簩缁寸爜");
       return;
     }
-    const data = await exportBagQr(params);
-    downloadFileFromBlobPart({ fileName: "琚嬬爜浜岀淮鐮�.zip", source: data });
+    const data = await (kind === 'business' ? exportBagBusinessQr : exportBagQr)(params);
+    downloadFileFromBlobPart({ fileName: kind === 'business' ? '琚嬬爜涓氬姟浜岀淮鐮�.zip' : '琚嬬爜杩芥函浜岀淮鐮�.zip', source: data });
   }
 
   /** 瀵煎嚭琚嬬爜 Excel锛堜氦浠樺嵃鍒凤級锛屽鍑哄悗琚嬬爜鐘舵�佸彉涓哄凡鍗板埛锛岄渶鍒锋柊鍒楄〃 */
@@ -319,73 +346,39 @@
     <BindPalletFormModal @success="handleRefresh" />
     <ReplaceFormModal @success="handleReplaceSuccess" />
     <QrTraceQueryModal />
+    <BusinessQrViewModal />
     <Grid table-title="琚嬬爜鍒楄〃锛堜竴琚嬩竴鐮侊級">
+      <template #table-title><span class="text-[1rem] font-bold" style="white-space:nowrap">琚嬬爜鍒楄〃锛堜竴琚嬩竴鐮侊級</span></template>
       <template #toolbar-tools>
-        <TableAction :actions="[
-            {
-              label: '鐢熸垚鏁版嵁鍖�',
-              type: 'primary',
-              icon: ACTION_ICON.ADD,
-              auth: ['mes:pro-bag-code:create'],
-              onClick: handleGenerate,
-            },
-            {
-              label: '鐢熸垚鍘熷琚嬬爜',
-              icon: ACTION_ICON.ADD,
-              auth: ['mes:pro-bag-code:create'],
-              onClick: handleRawGenerate,
-            },
-            {
-              label: '褰曞叆鎵规',
-              type: 'primary',
-              auth: ['mes:pro-bag-code:update'],
-              onClick: handleBindBatch,
-            },
-            {
-              label: '缁戝畾鎵樼洏',
-              type: 'primary',
-              auth: ['mes:pro-bag-code:update'],
-              onClick: handleBindPallet,
-            },
-            {
-              label: '鐮存崯鏇挎崲',
-              type: 'primary',
-              auth: ['mes:pro-bag-code:replace'],
-              onClick: handleReplace,
-            },
-            {
-              label: '瑙g粦鎵樼洏',
-              auth: ['mes:pro-bag-code:update'],
-              onClick: handleUnbindPallet,
-            },
-            {
-              label: '鎵爜杩芥函',
-              icon: ACTION_ICON.SEARCH,
-              auth: ['mes:pro-bag-code:query'],
-              onClick: handleTrace,
-            },
-            {
-              label: '瀵煎嚭浜岀淮鐮�',
-              icon: ACTION_ICON.DOWNLOAD,
-              auth: ['mes:pro-bag-code:export'],
-              onClick: handleExportQr,
-            },
-            {
-              label: $t('ui.actionTitle.export'),
-              type: 'primary',
-              icon: ACTION_ICON.DOWNLOAD,
-              auth: ['mes:pro-bag-code:export'],
-              onClick: handleExport,
-            },
-          ]" />
+        <div class="mes-code-toolbar">
+          <TableAction :actions="[{ label: '鐢熸垚鏁版嵁鍖�', type: 'primary', icon: ACTION_ICON.ADD, auth: ['mes:pro-bag-code:create'], onClick: handleGenerate },
+          { label: '褰曞叆鎵规', auth: ['mes:pro-bag-code:update'], onClick: handleBindBatch },
+          { label: '缁戝畾鎵樼洏', auth: ['mes:pro-bag-code:update'], onClick: handleBindPallet },
+          { label: '鎵爜杩芥函', icon: ACTION_ICON.SEARCH, auth: ['mes:pro-bag-code:query'], onClick: handleTrace }]" />
+          <TableAction :dropdown-trigger="['click']" :drop-down-actions="[{ label: '杩芥函浜岀淮鐮�', auth: ['mes:pro-bag-code:export'], onClick: () => handleExportQr('trace') },
+          { label: '涓氬姟浜岀淮鐮�', auth: ['mes:pro-bag-code:export'], onClick: () => handleExportQr('business') },
+          { label: 'Excel 鏁版嵁鍖�', auth: ['mes:pro-bag-code:export'], onClick: handleExport }]">
+            <template #more><Button>瀵煎嚭 <IconifyIcon icon="lucide:chevron-down" /></Button></template>
+          </TableAction>
+          <TableAction :dropdown-trigger="['click']" :drop-down-actions="[{ label: '鐢熸垚鍘熷琚嬬爜', auth: ['mes:pro-bag-code:create'], onClick: handleRawGenerate },
+          { label: '琛ョ敓鎴愪笟鍔$爜', auth: ['mes:pro-bag-code:create'], onClick: handleGenerateBusinessCodes },
+          { label: '鐮存崯鏇挎崲', auth: ['mes:pro-bag-code:replace'], onClick: handleReplace },
+          { label: '瑙g粦鎵樼洏', auth: ['mes:pro-bag-code:update'], onClick: handleUnbindPallet }]">
+            <template #more><Button>鏇村鎿嶄綔 <IconifyIcon icon="lucide:chevron-down" /></Button></template>
+          </TableAction>
+        </div>
       </template>
       <template #actions="{ row }">
         <TableAction :actions="[
             {
-              label: '鏌ョ湅浜岀淮鐮�',
+              label: '杩芥函浜岀淮鐮�',
               type: 'link',
               auth: ['mes:pro-bag-code:query'],
               onClick: handleViewQr.bind(null, row),
+            },
+            {
+              label: '涓氬姟浜岀淮鐮�', type: 'link', auth: ['mes:pro-bag-code:query'],
+              ifShow: !!row.businessCode, onClick: handleBusinessQr.bind(null, row),
             },
             {
               label: $t('common.delete'),
@@ -407,3 +400,9 @@
     </Grid>
   </Page>
 </template>
+
+<style scoped>
+.mes-code-toolbar { display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:8px; }
+.mes-code-toolbar :deep(.ant-btn) { white-space:nowrap; }
+.mes-code-toolbar :deep(.ant-btn > .iconify) { display:inline-block;width:14px;height:14px;vertical-align:middle; }
+</style>

--
Gitblit v1.9.3