From ee7ac8df8bce38add1f75baf876b49de94b9e00a Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期五, 16 十月 2026 17:58:33 +0800
Subject: [PATCH] feat(mes): 赋码管理绑定托盘支持未录入批次的袋码

---
 src/views/mes/pro/batch/index.vue |  126 ++++++++++++++++++++++++++++++-----------
 1 files changed, 92 insertions(+), 34 deletions(-)

diff --git a/src/views/mes/pro/batch/index.vue b/src/views/mes/pro/batch/index.vue
index 73dfe65..49e137d 100644
--- a/src/views/mes/pro/batch/index.vue
+++ b/src/views/mes/pro/batch/index.vue
@@ -6,24 +6,34 @@
   import { MesProBatchStatusEnum } from "@vben/constants";
   import { downloadFileFromBlobPart } from "@vben/utils";
 
-  import { Button, message } from "ant-design-vue";
+  import { Button, message, Modal, Tag } from "ant-design-vue";
 
   import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table";
   import {
     deleteBatch,
     exportBatchExcel,
     exportBatchQr,
+    exportBatchBusinessQr,
+    generateBatchBusinessCodes,
     getBatchPage,
     updateBatchStatus,
   } from "#/api/mes/pro/batch";
+  import { IconifyIcon } from "@vben/icons";
   import { $t } from "#/locales";
 
   import { useGridColumns, useGridFormSchema } from "./data";
   import Form from "./modules/form.vue";
+  import PreGenerateModal from "./modules/pre-generate.vue";
   import QrTraceModal from "../components/qr-trace-modal.vue";
+  import BusinessQrModal from "../components/business-qr.vue";
 
   const [FormModal, formModalApi] = useVbenModal({
     connectedComponent: Form,
+    destroyOnClose: true,
+  });
+
+  const [PreGenerateModalApi, preGenerateModalApi] = useVbenModal({
+    connectedComponent: PreGenerateModal,
     destroyOnClose: true,
   });
 
@@ -33,6 +43,21 @@
   });
 
   /** 鍒锋柊琛ㄦ牸 */
+  const [BusinessQrViewModal, businessQrApi] = useVbenModal({ connectedComponent: BusinessQrModal, destroyOnClose: true });
+  function handleBusinessQr(row: MesProBatchApi.Batch) {
+    businessQrApi.setData({ code: row.businessCode }).open();
+  }
+  async function handleGenerateBusiness(row: MesProBatchApi.Batch) {
+    if (row.id == null) return;
+    const count = await generateBatchBusinessCodes([row.id]);
+    message.success(`宸茶ˉ鐢熸垚 ${count} 浠戒笟鍔$爜锛屽凡鏈夌爜鍊间繚鎸佷笉鍙榒); handleRefresh();
+  }
+  async function handleExportBusiness(row: MesProBatchApi.Batch) {
+    if (row.id == null) return;
+    const data = await exportBatchBusinessQr(row.id);
+    downloadFileFromBlobPart({ fileName: '鎵规涓庢墭鐩樹笟鍔′簩缁寸爜.zip', source: data });
+  }
+
   function handleRefresh() {
     gridApi.query();
   }
@@ -42,23 +67,48 @@
     qrTraceQueryModalApi.open();
   }
 
-  /** 鏌ョ湅浜岀淮鐮侊紙琛屽唴棰勫~鐮佸�硷級 */
+  /** 鑾峰彇鎵规鏄剧ず鐢ㄧ殑鐮佸�硷紙姝e紡鎵规鍙蜂紭鍏堬紝鍏舵涓存椂鎵规鐮侊級 */
+  function getDisplayCode(row: MesProBatchApi.Batch) {
+    return row.code || row.tempCode || "";
+  }
+
+  /** 鏌ョ湅浜岀淮鐮侊紙琛屽唴棰勫~鐮佸�硷紝涓存椂鎵规鐢ㄤ复鏃舵壒娆$爜锛� */
   function handleViewQr(row: MesProBatchApi.Batch) {
-    qrTraceQueryModalApi.setData({ code: row.code }).open();
+    qrTraceQueryModalApi.setData({ code: getDisplayCode(row) }).open();
   }
 
   /** 鎵撳嵃鏁村浜岀淮鐮侊紙鎵规鍥� + 鍏ㄩ儴鎵樼洏鍥� ZIP锛� */
   async function handlePrintQrSet(row: MesProBatchApi.Batch) {
     const data = await exportBatchQr(row.id!);
     downloadFileFromBlobPart({
-      fileName: `鎵规浜岀淮鐮�-${row.code}.zip`,
+      fileName: `鎵规浜岀淮鐮�-${getDisplayCode(row)}.zip`,
       source: data,
+    });
+  }
+
+  /** 棰勭敓鎴愭壒娆′簩缁寸爜鎴愬姛锛氬埛鏂板垪琛ㄥ苟灞曠ず鐢熸垚鐨勪复鏃舵壒娆$爜 */
+  function handlePreGenerateSuccess(result: { id: number; tempCode: string }[]) {
+    handleRefresh();
+    Modal.success({
+      title: "棰勭敓鎴愪复鏃舵壒娆$爜鎴愬姛",
+      content: result.map((item) => item.tempCode).join("\n"),
+      centered: true,
     });
   }
 
   /** 鏂板鎵规 */
   function handleCreate() {
     formModalApi.setData({ formType: "create" }).open();
+  }
+
+  /** 涓存椂鎵规琛ュ綍姝e紡淇℃伅 */
+  function handleFillInfo(row: MesProBatchApi.Batch) {
+    formModalApi.setData({ formType: "fill", id: row.id }).open();
+  }
+
+  /** 棰勭敓鎴愭壒娆′簩缁寸爜 */
+  function handlePreGenerate() {
+    preGenerateModalApi.open();
   }
 
   /** 鏌ョ湅璇︽儏 */
@@ -74,7 +124,7 @@
   /** 鍒犻櫎鎵规 */
   async function handleDelete(row: MesProBatchApi.Batch) {
     await deleteBatch(row.id!);
-    message.success($t("ui.actionMessage.deleteSuccess", [row.code]));
+    message.success($t("ui.actionMessage.deleteSuccess", [getDisplayCode(row)]));
     handleRefresh();
   }
 
@@ -129,44 +179,42 @@
 <template>
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
+    <PreGenerateModalApi @success="handlePreGenerateSuccess" />
     <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: $t('ui.actionTitle.create', ['鎵规']),
-              type: 'primary',
-              icon: ACTION_ICON.ADD,
-              auth: ['mes:pro-batch:create'],
-              onClick: handleCreate,
-            },
-            {
-              label: '鎵爜杩芥函',
-              icon: ACTION_ICON.SEARCH,
-              auth: ['mes:pro-batch:query'],
-              onClick: handleTrace,
-            },
-            {
-              label: $t('ui.actionTitle.export'),
-              type: 'primary',
-              icon: ACTION_ICON.DOWNLOAD,
-              auth: ['mes:pro-batch:export'],
-              onClick: handleExport,
-            },
-          ]" />
+        <div class="mes-code-toolbar">
+          <TableAction :actions="[{ label: '棰勭敓鎴愪簩缁寸爜', type: 'primary', icon: ACTION_ICON.ADD, auth: ['mes:pro-batch:create'], onClick: handlePreGenerate },
+          { label: '鏂板鎵规', auth: ['mes:pro-batch:create'], onClick: handleCreate },
+          { label: '鎵爜杩芥函', icon: ACTION_ICON.SEARCH, auth: ['mes:pro-batch:query'], onClick: handleTrace }]" />
+          <TableAction :dropdown-trigger="['click']" :drop-down-actions="[{ label: 'Excel 鏁版嵁', auth: ['mes:pro-batch:export'], onClick: handleExport }]">
+            <template #more><Button>瀵煎嚭 <IconifyIcon icon="lucide:chevron-down" /></Button></template>
+          </TableAction>
+        </div>
       </template>
       <template #code="{ row }">
         <Button type="link" @click="handleDetail(row)">
-          {{ row.code }}
+          {{ getDisplayCode(row) }}
         </Button>
+        <Tag v-if="!row.code" color="warning">寰呰ˉ褰�</Tag>
       </template>
       <template #actions="{ row }">
         <TableAction :actions="[
             {
-              label: '鏌ョ湅浜岀淮鐮�',
+              label: '杩芥函浜岀淮鐮�',
               type: 'link',
               auth: ['mes:pro-batch:query'],
               onClick: handleViewQr.bind(null, row),
+            },
+            {
+              label: '琛ュ綍淇℃伅',
+              type: 'link',
+              icon: ACTION_ICON.EDIT,
+              auth: ['mes:pro-batch:update'],
+              ifShow: !row.code,
+              onClick: handleFillInfo.bind(null, row),
             },
             {
               label: $t('common.edit'),
@@ -174,8 +222,9 @@
               icon: ACTION_ICON.EDIT,
               auth: ['mes:pro-batch:update'],
               ifShow:
-                row.status === MesProBatchStatusEnum.DRAFT ||
-                row.status === MesProBatchStatusEnum.PRODUCING,
+                (row.status === MesProBatchStatusEnum.DRAFT ||
+                  row.status === MesProBatchStatusEnum.PRODUCING) &&
+                !!row.code,
               onClick: handleEdit.bind(null, row),
             },
             {
@@ -188,16 +237,19 @@
                 row.status === MesProBatchStatusEnum.DRAFT ||
                 row.status === MesProBatchStatusEnum.CANCELED,
               popConfirm: {
-                title: $t('ui.actionMessage.deleteConfirm', [row.code]),
+                title: $t('ui.actionMessage.deleteConfirm', [getDisplayCode(row)]),
                 confirm: handleDelete.bind(null, row),
               },
             },
           ]"
           :drop-down-actions="[
+            { label: '涓氬姟浜岀淮鐮�', auth: ['mes:pro-batch:query'], ifShow: !!row.businessCode, onClick: () => handleBusinessQr(row) },
+            { label: '琛ョ敓鎴愪笟鍔$爜', auth: ['mes:pro-batch:create'], ifShow: !row.businessCode && row.status !== MesProBatchStatusEnum.CANCELED, onClick: () => handleGenerateBusiness(row) },
+            { label: '瀵煎嚭鏁村涓氬姟浜岀淮鐮�', auth: ['mes:pro-batch:export'], ifShow: row.status !== MesProBatchStatusEnum.CANCELED, onClick: () => handleExportBusiness(row) },
             {
               label: '寮�濮嬬敓浜�',
               auth: ['mes:pro-batch:update'],
-              ifShow: row.status === MesProBatchStatusEnum.DRAFT,
+              ifShow: row.status === MesProBatchStatusEnum.DRAFT && !!row.code,
               popConfirm: {
                 title: '纭寮�濮嬬敓浜ц鎵规鍚楋紵',
                 confirm: () =>
@@ -227,7 +279,7 @@
               },
             },
             {
-              label: '鎵撳嵃鏁村浜岀淮鐮�',
+              label: '鎵撳嵃鏁村杩芥函浜岀淮鐮�',
               auth: ['mes:pro-batch:export'],
               onClick: () => handlePrintQrSet(row),
             },
@@ -236,3 +288,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