From 08bb5d242135e2c1f0fc17d2b5f7ae548275a3a2 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期五, 28 八月 2026 17:15:33 +0800
Subject: [PATCH] feat(mes): 实现临时码预生成和补录功能

---
 src/views/mes/pro/pallet/data.ts                    |    5 
 src/views/mes/pro/bagCode/index.vue                 |   29 ++
 src/views/mes/pro/batch/index.vue                   |   67 ++++
 src/views/mes/pro/batch/modules/pre-generate.vue    |   80 ++++++
 src/views/mes/pro/pallet/modules/bind-batch.vue     |   88 ++++++
 src/views/mes/pro/batch/modules/form.vue            |   16 +
 src/api/mes/pro/pallet/index.ts                     |   38 ++
 src/api/mes/pro/batch/index.ts                      |   29 ++
 src/views/mes/pro/pallet/index.vue                  |  102 +++++++
 src/views/mes/pro/bagCode/modules/bind-batch.vue    |   62 ++++
 src/api/mes/pro/bagCode/index.ts                    |   20 +
 src/views/mes/pro/bagCode/data.ts                   |    2 
 src/views/mes/pro/pallet/modules/generate-form.vue  |  125 +++------
 src/views/mes/pro/bagCode/modules/generate-form.vue |   29 --
 src/views/mes/pro/batch/data.ts                     |   21 +
 src/views/mes/pro/components/qr-trace-modal.vue     |   44 ++
 16 files changed, 613 insertions(+), 144 deletions(-)

diff --git a/src/api/mes/pro/bagCode/index.ts b/src/api/mes/pro/bagCode/index.ts
index 5c381e9..22d4b6e 100644
--- a/src/api/mes/pro/bagCode/index.ts
+++ b/src/api/mes/pro/bagCode/index.ts
@@ -36,9 +36,17 @@
 
   /** 鐢熸垚鏁版嵁鍖呰姹� */
   export interface GenerateParams {
-    batchId: number; // 鐢熶骇鎵规缂栧彿
     count: number; // 鐢熸垚琚嬫暟
     remark?: string; // 澶囨敞
+  }
+
+  export interface GenerateResult {
+    uuid?: string;
+  }
+
+  export interface BindBatchParams {
+    batchId: number;
+    ids: number[];
   }
 
   /** 缁戝畾/瑙g粦鎵樼洏璇锋眰 */
@@ -111,7 +119,15 @@
 
 /** 鐢熸垚琚嬬爜鏁版嵁鍖咃紙杩斿洖鐢熸垚缁� UUID锛� */
 export function generateBagCodes(data: MesProBagCodeApi.GenerateParams) {
-  return requestClient.post<string>('/mes/pro/bag-code/generate', data);
+  return requestClient.post<MesProBagCodeApi.GenerateResult>(
+    '/mes/pro/bag-code/generate',
+    data,
+  );
+}
+
+/** 褰曞叆鐢熶骇鎵规 */
+export function bindBagCodeBatch(data: MesProBagCodeApi.BindBatchParams) {
+  return requestClient.put('/mes/pro/bag-code/bind-batch', data);
 }
 
 /** 鍒犻櫎琚嬬爜鐢熸垚缁� */
diff --git a/src/api/mes/pro/batch/index.ts b/src/api/mes/pro/batch/index.ts
index 01e4424..86544c8 100644
--- a/src/api/mes/pro/batch/index.ts
+++ b/src/api/mes/pro/batch/index.ts
@@ -18,7 +18,8 @@
   /** 鐢熶骇鎵规 */
   export interface Batch {
     id?: number; // 缂栧彿
-    code?: string; // 鎵规鍙凤紙鑷姩鐢熸垚锛�
+    code?: string; // 鎵规鍙凤紙琛ュ綍姝e紡淇℃伅鍚庤嚜鍔ㄧ敓鎴愶級
+    tempCode?: string; // 涓存椂鎵规鐮侊紙棰勭敓鎴愪簩缁寸爜闃舵浣跨敤锛屾壂鐮佽拷婧吋瀹癸級
     itemId?: number; // 鍝佺锛堜骇鍝佺墿鏂欙級缂栧彿
     itemCode?: string; // 鍝佺缂栫爜锛堝悗绔嫾鎺ワ級
     itemName?: string; // 鍝佺鍚嶇О锛堝悗绔嫾鎺ワ級
@@ -41,7 +42,8 @@
   /** 鐢熶骇鎵规鎵爜杩芥函 */
   export interface BatchTrace {
     id?: number; // 鐢熶骇鎵规缂栧彿
-    code?: string; // 鎵规鍙凤紙浜岀淮鐮佸唴瀹癸級
+    code?: string; // 鎵规鍙凤紙琛ュ綍鍚庣殑姝e紡鎵规鍙凤級
+    tempCode?: string; // 涓存椂鎵规鐮侊紙浜岀淮鐮佸唴瀹癸紱鏈ˉ褰曚俊鎭椂灞曠ず锛�
     status?: number; // 鎵规鐘舵�侊紙瀛楀吀 mes_pro_batch_status锛�
     produceDate?: string; // 鐢熶骇鏃ユ湡
     lineCode?: string; // 浜х嚎缂栫爜
@@ -65,6 +67,7 @@
   /** 鐢熶骇鎵规鍒嗛〉鏌ヨ鍙傛暟 */
   export interface PageParams extends PageParam {
     code?: string;
+    tempCode?: string;
     itemId?: number;
     lineId?: number;
     lineCode?: string;
@@ -73,6 +76,12 @@
     status?: number;
     produceDate?: string[];
     createTime?: string[];
+  }
+
+  /** 棰勭敓鎴愭壒娆′簩缁寸爜杩斿洖椤� */
+  export interface PreGenerateResult {
+    id: number; // 鐢熶骇鎵规缂栧彿
+    tempCode: string; // 涓存椂鎵规鐮侊紙浜岀淮鐮佸唴瀹癸級
   }
 }
 
@@ -91,6 +100,22 @@
   );
 }
 
+/** 棰勭敓鎴愭壒娆′复鏃朵簩缁寸爜锛堜粎鐢熸垚涓存椂鎵规鐮侊紝涓嶅綍鍏ヤ笟鍔′俊鎭級 */
+export function preGenerateBatch(data: {
+  count: number;
+  remark?: string;
+}) {
+  return requestClient.post<MesProBatchApi.PreGenerateResult[]>(
+    '/mes/pro/batch/pre-generate',
+    data,
+  );
+}
+
+/** 琛ュ綍鎵规姝e紡淇℃伅锛堢敓鎴愭寮忔壒娆″彿锛� */
+export function fillBatchInfo(data: MesProBatchApi.Batch) {
+  return requestClient.put('/mes/pro/batch/fill-info', data);
+}
+
 /** 鏂板鐢熶骇鎵规锛堣嚜鍔ㄧ敓鎴愭壒娆″彿锛� */
 export function createBatch(data: MesProBatchApi.Batch) {
   return requestClient.post<number>('/mes/pro/batch/create', data);
diff --git a/src/api/mes/pro/pallet/index.ts b/src/api/mes/pro/pallet/index.ts
index 2fef83b..7ae540b 100644
--- a/src/api/mes/pro/pallet/index.ts
+++ b/src/api/mes/pro/pallet/index.ts
@@ -7,7 +7,8 @@
   /** 鎵樼洏鐮� */
   export interface Pallet {
     id?: number; // 缂栧彿
-    code?: string; // 鎵樼洏鐮�
+    code?: string; // 鎵樼洏鐮侊紙缁戝畾鎵规鍚庣敓鎴愶級
+    tempCode?: string; // 涓存椂鎵樼洏鐮侊紙棰勭敓鎴愪簩缁寸爜闃舵浣跨敤锛屾壂鐮佽拷婧吋瀹癸級
     batchId?: number; // 鐢熶骇鎵规缂栧彿
     batchCode?: string; // 鎵规鍙�
     palletNo?: number; // 鎵规鍐呮墭鐩樺簭鍙�
@@ -21,6 +22,7 @@
   /** 鎵樼洏鐮佸垎椤垫煡璇㈠弬鏁� */
   export interface PageParams extends PageParam {
     code?: string;
+    tempCode?: string;
     batchId?: number;
     batchCode?: string;
     status?: number;
@@ -30,7 +32,8 @@
   /** 鎵樼洏鐮佹壂鐮佽拷婧� */
   export interface PalletTrace {
     id?: number; // 缂栧彿
-    code?: string; // 鎵樼洏鐮侊紙浜岀淮鐮佸唴瀹癸級
+    code?: string; // 鎵樼洏鐮侊紙缁戝畾鎵规鍚庣殑姝e紡鎵樼洏鐮侊級
+    tempCode?: string; // 涓存椂鎵樼洏鐮侊紙浜岀淮鐮佸唴瀹癸紱鏈粦瀹氭壒娆℃椂灞曠ず锛�
     palletNo?: number; // 鎵规鍐呮墭鐩樺簭鍙�
     capacity?: number; // 鍙琚嬫暟
     bagCount?: number; // 宸茬粦瀹氳鐮佹暟閲�
@@ -58,11 +61,34 @@
     capacity?: number; // 鍙琚嬫暟
     remark?: string; // 澶囨敞
   }
+
+  /** 棰勭敓鎴愭墭鐩樹簩缁寸爜杩斿洖椤� */
+  export interface PreGenerateResult {
+    id: number; // 鎵樼洏鐮佺紪鍙�
+    tempCode: string; // 涓存椂鎵樼洏鐮侊紙浜岀淮鐮佸唴瀹癸級
+  }
 }
 
 /** 鎵归噺鐢熸垚鎵樼洏鐮侊紙杩斿洖鐢熸垚鐨勬墭鐩樼紪鍙峰垪琛級 */
 export function batchCreatePallet(data: MesProPalletApi.BatchCreateParams) {
   return requestClient.post<number[]>('/mes/pro/pallet/batch-create', data);
+}
+
+/** 棰勭敓鎴愭墭鐩樹复鏃朵簩缁寸爜锛堜笉缁戝畾鐢熶骇鎵规锛� */
+export function preGeneratePallet(data: {
+  count: number;
+  capacity?: number;
+  remark?: string;
+}) {
+  return requestClient.post<MesProPalletApi.PreGenerateResult[]>(
+    '/mes/pro/pallet/pre-generate',
+    data,
+  );
+}
+
+/** 鎵樼洏鐮佺粦瀹氱敓浜ф壒娆★紙鐢熸垚姝e紡鎵樼洏鐮侊級 */
+export function bindPalletBatch(data: { ids: number[]; batchId: number }) {
+  return requestClient.put('/mes/pro/pallet/bind-batch', data);
 }
 
 /** 鍒犻櫎鎵樼洏鐮� */
@@ -108,3 +134,11 @@
 export function exportPalletQr(batchId: number) {
   return requestClient.download(`/mes/pro/pallet/export-qr?batchId=${batchId}`);
 }
+
+/** 鎸夋墭鐩樼爜缂栧彿鍒楄〃鎵归噺瀵煎嚭浜岀淮鐮佸浘鐗� ZIP */
+export function exportPalletQrByIds(ids: number[]) {
+  return requestClient.download('/mes/pro/pallet/export-qr-by-ids', {
+    method: 'POST',
+    data: { ids },
+  });
+}
diff --git a/src/views/mes/pro/bagCode/data.ts b/src/views/mes/pro/bagCode/data.ts
index a2b312e..caacb5f 100644
--- a/src/views/mes/pro/bagCode/data.ts
+++ b/src/views/mes/pro/bagCode/data.ts
@@ -133,7 +133,7 @@
     },
     {
       title: '鎿嶄綔',
-      width: 200,
+      width: 350,
       fixed: 'right',
       slots: { default: 'actions' },
     },
diff --git a/src/views/mes/pro/bagCode/index.vue b/src/views/mes/pro/bagCode/index.vue
index 910602c..58621ab 100644
--- a/src/views/mes/pro/bagCode/index.vue
+++ b/src/views/mes/pro/bagCode/index.vue
@@ -14,11 +14,13 @@
     exportBagCodeExcel,
     exportBagQr,
     getBagCodePage,
+    bindBagCodeBatch,
     unbindBagCodePallet,
   } from "#/api/mes/pro/bagCode";
   import { $t } from "#/locales";
 
   import { useGridColumns, useGridFormSchema } from "./data";
+  import BindBatchModal from "./modules/bind-batch.vue";
   import BindPalletModal from "./modules/bind-pallet.vue";
   import GenerateModal from "./modules/generate-form.vue";
   import ReplaceModal from "./modules/replace-form.vue";
@@ -28,6 +30,11 @@
 
   const [GenerateFormModal, generateFormModalApi] = useVbenModal({
     connectedComponent: GenerateModal,
+    destroyOnClose: true,
+  });
+
+  const [BindBatchFormModal, bindBatchFormModalApi] = useVbenModal({
+    connectedComponent: BindBatchModal,
     destroyOnClose: true,
   });
 
@@ -178,10 +185,25 @@
       .open();
   }
 
+  /** 鎵归噺褰曞叆鐢熶骇鎵规 */
+  function handleBindBatch() {
+    const records = getSelectedRecords();
+    if (!records) return;
+    if (records.some((record) => record.status !== MesProBagCodeStatusEnum.GENERATED || record.batchId)) {
+      message.warning("璇烽�夋嫨鏈綍鍏ユ壒娆′笖鐘舵�佷负宸茬敓鎴愮殑琚嬬爜");
+      return;
+    }
+    bindBatchFormModalApi.setData({ ids: records.map((record) => record.id!) }).open();
+  }
+
   /** 鎵归噺缁戝畾鎵樼洏 */
   function handleBindPallet() {
     const records = getSelectedRecords();
     if (!records) return;
+    if (records.some((record) => !record.batchId)) {
+      message.warning("璇峰厛褰曞叆鐢熶骇鎵规锛屽啀缁戝畾鎵樼洏");
+      return;
+    }
     const batchIds = new Set(records.map((record) => record.batchId));
     if (batchIds.size > 1) {
       message.warning("璇烽�夋嫨鍚屼竴鎵规涓嬬殑琚嬬爜杩涜缁戝畾");
@@ -281,6 +303,7 @@
 <template>
   <Page auto-content-height>
     <GenerateFormModal @success="handleRefresh" />
+    <BindBatchFormModal @success="handleRefresh" />
     <BindPalletFormModal @success="handleRefresh" />
     <ReplaceFormModal @success="handleReplaceSuccess" />
     <QrTraceQueryModal />
@@ -295,6 +318,12 @@
               onClick: handleGenerate,
             },
             {
+              label: '褰曞叆鎵规',
+              type: 'primary',
+              auth: ['mes:pro-bag-code:update'],
+              onClick: handleBindBatch,
+            },
+            {
               label: '缁戝畾鎵樼洏',
               type: 'primary',
               auth: ['mes:pro-bag-code:update'],
diff --git a/src/views/mes/pro/bagCode/modules/bind-batch.vue b/src/views/mes/pro/bagCode/modules/bind-batch.vue
new file mode 100644
index 0000000..9e2683e
--- /dev/null
+++ b/src/views/mes/pro/bagCode/modules/bind-batch.vue
@@ -0,0 +1,62 @@
+<script lang="ts" setup>
+  import type { VbenFormSchema } from "#/adapter/form";
+
+  import { useVbenModal } from "@vben/common-ui";
+  import { MesProBatchStatusEnum } from "@vben/constants";
+  import { message } from "ant-design-vue";
+
+  import { useVbenForm } from "#/adapter/form";
+  import { bindBagCodeBatch } from "#/api/mes/pro/bagCode";
+  import { getBatchSimpleList } from "#/api/mes/pro/batch";
+  import { $t } from "#/locales";
+
+  defineOptions({ name: "MesProBagCodeBindBatch" });
+
+  interface ModalData { ids: number[] }
+  const emit = defineEmits(["success"]);
+
+  const [Form, formApi] = useVbenForm({
+    commonConfig: { componentProps: { class: "w-full" }, labelWidth: 100 },
+    layout: "horizontal", schema: [], showDefaultActions: false,
+  });
+
+  const [Modal, modalApi] = useVbenModal({
+    async onConfirm() {
+      const { valid } = await formApi.validate();
+      if (!valid) return;
+      const data = modalApi.getData<ModalData>();
+      const values = await formApi.getValues();
+      modalApi.lock();
+      try {
+        await bindBagCodeBatch({ batchId: values.batchId, ids: data.ids });
+        message.success($t("ui.actionMessage.operationSuccess"));
+        emit("success");
+        await modalApi.close();
+      } finally { modalApi.unlock(); }
+    },
+    async onOpenChange(isOpen: boolean) {
+      if (!isOpen) return;
+      modalApi.lock();
+      try {
+        const batches = await getBatchSimpleList();
+        // 浠呭凡琛ュ綍姝e紡淇℃伅锛堟壒娆″彿闈炵┖锛変笖鐢熶骇涓殑鎵规鍏佽褰曞叆琚嬬爜
+        const options = batches
+          .filter(
+            (batch) =>
+              batch.status === MesProBatchStatusEnum.PRODUCING && batch.code,
+          )
+          .map((batch) => ({ label: batch.code!, value: batch.id! }));
+        const schema: VbenFormSchema[] = [{
+          fieldName: "batchId", label: "鐢熶骇鎵规", component: "Select",
+          componentProps: { options, optionFilterProp: "label", placeholder: "璇烽�夋嫨鐢熶骇涓殑鎵规", showSearch: true },
+          rules: "selectRequired",
+        }];
+        await formApi.setState({ schema });
+      } finally { modalApi.unlock(); }
+    },
+  });
+</script>
+
+<template>
+  <Modal title="褰曞叆鐢熶骇鎵规" class="w-2/5"><Form class="mx-4" /></Modal>
+</template>
diff --git a/src/views/mes/pro/bagCode/modules/generate-form.vue b/src/views/mes/pro/bagCode/modules/generate-form.vue
index 6ea36bc..316e9fd 100644
--- a/src/views/mes/pro/bagCode/modules/generate-form.vue
+++ b/src/views/mes/pro/bagCode/modules/generate-form.vue
@@ -3,33 +3,18 @@
   import type { MesProBagCodeApi } from "#/api/mes/pro/bagCode";
 
   import { useVbenModal } from "@vben/common-ui";
-  import { MesProBatchStatusEnum } from "@vben/constants";
 
   import { message } from "ant-design-vue";
 
   import { useVbenForm } from "#/adapter/form";
   import { generateBagCodes } from "#/api/mes/pro/bagCode";
-  import { getBatchSimpleList } from "#/api/mes/pro/batch";
 
   defineOptions({ name: "MesProBagCodeGenerateForm" });
 
   const emit = defineEmits(["success"]);
 
-  /** 鏋勫缓琛ㄥ崟锛堟壒娆′笅鎷夐�夐」鐢卞閮ㄥ姞杞芥敞鍏ワ級 */
-  function buildSchema(batchOptions: { label: string; value: number }[]): VbenFormSchema[] {
+  function buildSchema(): VbenFormSchema[] {
     return [
-      {
-        fieldName: "batchId",
-        label: "鐢熶骇鎵规",
-        component: "Select",
-        componentProps: {
-          options: batchOptions,
-          optionFilterProp: "label",
-          placeholder: "璇烽�夋嫨鐢熶骇涓殑鎵规",
-          showSearch: true,
-        },
-        rules: "selectRequired",
-      },
       {
         fieldName: "count",
         label: "鐢熸垚琚嬫暟",
@@ -86,17 +71,7 @@
       if (!isOpen) return;
       modalApi.lock();
       try {
-        // 浠呯敓浜т腑鐨勬壒娆″厑璁哥敓鎴愯鐮�
-        const batches = await getBatchSimpleList();
-        const options = batches
-          .filter(
-            (batch) => batch.status === MesProBatchStatusEnum.PRODUCING
-          )
-          .map((batch) => ({
-            label: batch.code!,
-            value: batch.id!,
-          }));
-        await formApi.setState({ schema: buildSchema(options) });
+        await formApi.setState({ schema: buildSchema() });
       } finally {
         modalApi.unlock();
       }
diff --git a/src/views/mes/pro/batch/data.ts b/src/views/mes/pro/batch/data.ts
index 1b765a7..673aedc 100644
--- a/src/views/mes/pro/batch/data.ts
+++ b/src/views/mes/pro/batch/data.ts
@@ -12,8 +12,8 @@
 import { UserSelect } from '#/views/system/user/components';
 import { getRangePickerDefaultProps } from '#/utils';
 
-/** 琛ㄥ崟绫诲瀷 */
-export type FormType = 'create' | 'detail' | 'update';
+/** 琛ㄥ崟绫诲瀷锛坒ill锛氫复鏃舵壒娆$爜琛ュ綍姝e紡淇℃伅锛� */
+export type FormType = 'create' | 'detail' | 'update' | 'fill';
 
 /** 鏂板/淇敼鐨勮〃鍗� */
 export function useFormSchema(formType: FormType): VbenFormSchema[] {
@@ -33,11 +33,24 @@
       component: 'Input',
       componentProps: {
         disabled: true,
-        placeholder: '淇濆瓨鍚庤嚜鍔ㄧ敓鎴�',
+        placeholder: '琛ュ綍鍚庤嚜鍔ㄧ敓鎴�',
       },
       dependencies: {
         triggerFields: [''],
         show: () => formType !== 'create',
+      },
+    },
+    {
+      fieldName: 'tempCode',
+      label: '涓存椂鎵规鐮�',
+      component: 'Input',
+      componentProps: {
+        disabled: true,
+        placeholder: '棰勭敓鎴愪簩缁寸爜闃舵浣跨敤鐨勪复鏃剁爜',
+      },
+      dependencies: {
+        triggerFields: [''],
+        show: () => formType === 'fill',
       },
     },
     {
@@ -273,7 +286,7 @@
     },
     {
       title: '鎿嶄綔',
-      width: 300,
+      width: 350,
       fixed: 'right',
       slots: { default: 'actions' },
     },
diff --git a/src/views/mes/pro/batch/index.vue b/src/views/mes/pro/batch/index.vue
index 73dfe65..99ff585 100644
--- a/src/views/mes/pro/batch/index.vue
+++ b/src/views/mes/pro/batch/index.vue
@@ -6,7 +6,7 @@
   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 {
@@ -20,10 +20,16 @@
 
   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";
 
   const [FormModal, formModalApi] = useVbenModal({
     connectedComponent: Form,
+    destroyOnClose: true,
+  });
+
+  const [PreGenerateModalApi, preGenerateModalApi] = useVbenModal({
+    connectedComponent: PreGenerateModal,
     destroyOnClose: true,
   });
 
@@ -42,23 +48,47 @@
     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 }[]) {
+    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 +104,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,10 +159,17 @@
 <template>
   <Page auto-content-height>
     <FormModal @success="handleRefresh" />
+    <PreGenerateModalApi @success="handlePreGenerateSuccess" />
     <QrTraceQueryModal />
     <Grid table-title="鐢熶骇鎵规鍒楄〃">
       <template #toolbar-tools>
         <TableAction :actions="[
+            {
+              label: '棰勭敓鎴愪簩缁寸爜',
+              icon: ACTION_ICON.ADD,
+              auth: ['mes:pro-batch:create'],
+              onClick: handlePreGenerate,
+            },
             {
               label: $t('ui.actionTitle.create', ['鎵规']),
               type: 'primary',
@@ -157,8 +194,9 @@
       </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="[
@@ -169,13 +207,22 @@
               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'),
               type: 'link',
               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,7 +235,7 @@
                 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),
               },
             },
@@ -197,7 +244,7 @@
             {
               label: '寮�濮嬬敓浜�',
               auth: ['mes:pro-batch:update'],
-              ifShow: row.status === MesProBatchStatusEnum.DRAFT,
+              ifShow: row.status === MesProBatchStatusEnum.DRAFT && !!row.code,
               popConfirm: {
                 title: '纭寮�濮嬬敓浜ц鎵规鍚楋紵',
                 confirm: () =>
diff --git a/src/views/mes/pro/batch/modules/form.vue b/src/views/mes/pro/batch/modules/form.vue
index 2e45243..6242291 100644
--- a/src/views/mes/pro/batch/modules/form.vue
+++ b/src/views/mes/pro/batch/modules/form.vue
@@ -15,7 +15,12 @@
 
   import { useVbenForm } from "#/adapter/form";
   import { TableAction, useVbenVxeGrid } from "#/adapter/vxe-table";
-  import { createBatch, getBatch, updateBatch } from "#/api/mes/pro/batch";
+  import {
+    createBatch,
+    fillBatchInfo,
+    getBatch,
+    updateBatch,
+  } from "#/api/mes/pro/batch";
   import { $t } from "#/locales";
   import { UserSelect } from "#/views/system/user/components";
 
@@ -33,7 +38,7 @@
   const formData = ref<MesProBatchApi.Batch>();
 
   const isEditable = computed(() =>
-    ["create", "update"].includes(formType.value)
+    ["create", "update", "fill"].includes(formType.value)
   );
 
   const getTitle = computed(() => {
@@ -43,6 +48,9 @@
       }
       case "update": {
         return $t("ui.actionTitle.edit", ["鐢熶骇鎵规"]);
+      }
+      case "fill": {
+        return "琛ュ綍鎵规淇℃伅";
       }
       default: {
         return $t("ui.actionTitle.create", ["鐢熶骇鎵规"]);
@@ -177,7 +185,9 @@
       modalApi.lock();
       try {
         const data = (await formApi.getValues()) as MesProBatchApi.Batch;
-        if (formData.value?.id) {
+        if (formType.value === "fill") {
+          await fillBatchInfo({ ...data, id: formData.value!.id, workers });
+        } else if (formData.value?.id) {
           await updateBatch({ ...data, id: formData.value.id, workers });
         } else {
           await createBatch({ ...data, workers });
diff --git a/src/views/mes/pro/batch/modules/pre-generate.vue b/src/views/mes/pro/batch/modules/pre-generate.vue
new file mode 100644
index 0000000..ebb1725
--- /dev/null
+++ b/src/views/mes/pro/batch/modules/pre-generate.vue
@@ -0,0 +1,80 @@
+<script lang="ts" setup>
+  import type { VbenFormSchema } from "#/adapter/form";
+  import type { MesProBatchApi } from "#/api/mes/pro/batch";
+
+  import { useVbenModal } from "@vben/common-ui";
+
+  import { message } from "ant-design-vue";
+
+  import { useVbenForm } from "#/adapter/form";
+  import { preGenerateBatch } from "#/api/mes/pro/batch";
+
+  defineOptions({ name: "MesProBatchPreGenerate" });
+
+  const emit = defineEmits(["success"]);
+
+  const [Form, formApi] = useVbenForm({
+    commonConfig: {
+      componentProps: {
+        class: "w-full",
+      },
+      labelWidth: 100,
+    },
+    layout: "horizontal",
+    schema: [],
+    showDefaultActions: false,
+  });
+
+  const [Modal, modalApi] = useVbenModal({
+    async onConfirm() {
+      const { valid } = await formApi.validate();
+      if (!valid) return;
+      modalApi.lock();
+      try {
+        const values = await formApi.getValues();
+        const result = await preGenerateBatch({
+          count: values.count,
+          remark: values.remark,
+        });
+        message.success(`宸茬敓鎴� ${result.length} 涓复鏃舵壒娆$爜`);
+        emit("success", result);
+        await modalApi.close();
+      } finally {
+        modalApi.unlock();
+      }
+    },
+    onOpenChange(isOpen: boolean) {
+      if (!isOpen) return;
+      const schema: VbenFormSchema[] = [
+        {
+          fieldName: "count",
+          label: "鐢熸垚涓暟",
+          component: "InputNumber",
+          componentProps: {
+            class: "!w-full",
+            min: 1,
+            placeholder: "璇疯緭鍏ラ渶瑕佺敓鎴愮殑鎵规涓暟",
+            precision: 0,
+          },
+          rules: "required",
+        },
+        {
+          fieldName: "remark",
+          label: "澶囨敞",
+          component: "Textarea",
+          componentProps: {
+            placeholder: "璇疯緭鍏ュ娉�",
+            rows: 2,
+          },
+        },
+      ];
+      formApi.setState({ schema });
+    },
+  });
+</script>
+
+<template>
+  <Modal title="棰勭敓鎴愭壒娆′簩缁寸爜" class="w-2/5">
+    <Form class="mx-4" />
+  </Modal>
+</template>
\ No newline at end of file
diff --git a/src/views/mes/pro/components/qr-trace-modal.vue b/src/views/mes/pro/components/qr-trace-modal.vue
index 710a2e7..f94946a 100644
--- a/src/views/mes/pro/components/qr-trace-modal.vue
+++ b/src/views/mes/pro/components/qr-trace-modal.vue
@@ -35,13 +35,19 @@
 
   const traceTypeLabel = ref("");
 
-  /** 璇嗗埆浜岀淮鐮佸唴瀹圭被鍨嬶細鎵规鍙� / 鎵樼洏鐮� / 琚嬬爜 */
+  /** 璇嗗埆浜岀淮鐮佸唴瀹圭被鍨嬶細鎵规鍙凤紙鍚复鏃舵壒娆$爜锛�/ 鎵樼洏鐮侊紙鍚复鏃舵墭鐩樼爜锛�/ 琚嬬爜 */
   function resolveCodeType(raw: string): TraceType | undefined {
     const value = raw.trim().toUpperCase();
+    if (/^PB-\d{8}$/.test(value)) {
+      return "batch";
+    }
+    if (/^PL-\d{8}$/.test(value)) {
+      return "pallet";
+    }
     if (/^.*-P\d{2}$/.test(value)) {
       return "pallet";
     }
-    if (/^.*-\d{4}$/.test(value)) {
+    if (/^BAG-\d{8}$/.test(value) || /^.*-\d{4}$/.test(value)) {
       return "bag";
     }
     return "batch";
@@ -125,7 +131,7 @@
     if (traceType.value === "pallet" && palletTrace.value) {
       const d = palletTrace.value;
       return [
-        { label: "鎵樼洏鐮�", value: d.code || "" },
+        { label: "鎵樼洏鐮�", value: d.code || d.tempCode || "" },
         { label: "鎵樼洏搴忓彿", value: d.palletNo ? String(d.palletNo) : "" },
         { label: "鎵规鍙�", value: d.batchCode || "" },
         { label: "鍝佺", value: d.itemName || "" },
@@ -141,7 +147,7 @@
     if (batchTrace.value) {
       const d = batchTrace.value;
       return [
-        { label: "鎵规鍙�", value: d.code || "" },
+        { label: "鎵规鍙�", value: d.code || d.tempCode || "" },
         { label: "鍝佺", value: d.itemName || "" },
         { label: "瑙勬牸", value: d.itemSpecification || "" },
         {
@@ -357,7 +363,12 @@
     schema: [
       {
         field: "code",
-        label: "鎵樼洏鐮侊紙浜岀淮鐮佸唴瀹癸級",
+        label: "鎵樼洏鐮侊紙姝e紡鎵樼洏鐮侊級",
+        span: 2,
+      },
+      {
+        field: "tempCode",
+        label: "涓存椂鎵樼洏鐮侊紙鏈粦瀹氭壒娆★級",
         span: 2,
       },
       {
@@ -419,7 +430,12 @@
     schema: [
       {
         field: "code",
-        label: "鎵规鍙凤紙浜岀淮鐮佸唴瀹癸級",
+        label: "鎵规鍙凤紙姝e紡鎵规鍙凤級",
+        span: 2,
+      },
+      {
+        field: "tempCode",
+        label: "涓存椂鎵规鐮侊紙寰呰ˉ褰曪級",
         span: 2,
       },
       {
@@ -502,6 +518,22 @@
               <p class="text-lg font-bold break-all">{{ currentCode }}</p>
               <p class="mt-1 text-xs text-gray-500">
                 鐮佺被鍨嬶細{{ traceTypeLabel }}
+                <Tag
+                  v-if="traceType === 'batch' && batchTrace && !batchTrace.code"
+                  color="warning"
+                  class="ml-2"
+                >
+                  寰呰ˉ褰�
+                </Tag>
+                <Tag
+                  v-else-if="
+                    traceType === 'pallet' && palletTrace && !palletTrace.code
+                  "
+                  color="warning"
+                  class="ml-2"
+                >
+                  鏈粦瀹氭壒娆�
+                </Tag>
               </p>
             </div>
           </div>
diff --git a/src/views/mes/pro/pallet/data.ts b/src/views/mes/pro/pallet/data.ts
index c7f1ac0..7ac44fb 100644
--- a/src/views/mes/pro/pallet/data.ts
+++ b/src/views/mes/pro/pallet/data.ts
@@ -53,11 +53,13 @@
 /** 鍒楄〃鐨勫瓧娈� */
 export function useGridColumns(): VxeTableGridOptions<MesProPalletApi.Pallet>['columns'] {
   return [
+    { type: 'checkbox', width: 50 },
     {
       field: 'code',
       title: '鎵樼洏鐮�',
       fixed: 'left',
       minWidth: 210,
+      slots: { default: 'code' },
     },
     {
       field: 'palletNo',
@@ -68,6 +70,7 @@
       field: 'batchCode',
       title: '鎵规鍙�',
       minWidth: 190,
+      slots: { default: 'batchCode' },
     },
     {
       field: 'capacity',
@@ -101,7 +104,7 @@
     },
     {
       title: '鎿嶄綔',
-      width: 200,
+      width: 350,
       fixed: 'right',
       slots: { default: 'actions' },
     },
diff --git a/src/views/mes/pro/pallet/index.vue b/src/views/mes/pro/pallet/index.vue
index 403a339..a34a272 100644
--- a/src/views/mes/pro/pallet/index.vue
+++ b/src/views/mes/pro/pallet/index.vue
@@ -5,18 +5,20 @@
   import { Page, useVbenModal } from "@vben/common-ui";
   import { downloadFileFromBlobPart } from "@vben/utils";
 
-  import { message } from "ant-design-vue";
+  import { message, Modal, Tag } from "ant-design-vue";
 
   import { ACTION_ICON, TableAction, useVbenVxeGrid } from "#/adapter/vxe-table";
   import {
     deletePallet,
     exportPalletExcel,
     exportPalletQr,
+    exportPalletQrByIds,
     getPalletPage,
   } from "#/api/mes/pro/pallet";
   import { $t } from "#/locales";
 
   import { useGridColumns, useGridFormSchema } from "./data";
+  import BindBatchModal from "./modules/bind-batch.vue";
   import GenerateModal from "./modules/generate-form.vue";
   import QrTraceModal from "../components/qr-trace-modal.vue";
 
@@ -24,6 +26,11 @@
 
   const [GenerateFormModal, generateFormModalApi] = useVbenModal({
     connectedComponent: GenerateModal,
+    destroyOnClose: true,
+  });
+
+  const [BindBatchFormModal, bindBatchFormModalApi] = useVbenModal({
+    connectedComponent: BindBatchModal,
     destroyOnClose: true,
   });
 
@@ -37,9 +44,18 @@
     gridApi.query();
   }
 
-  /** 鎵归噺鐢熸垚鎵樼洏鐮� */
+  /** 鎵归噺棰勭敓鎴愭墭鐩樼爜 */
   function handleCreate() {
     generateFormModalApi.open();
+  }
+
+  /** 棰勭敓鎴愭垚鍔燂細灞曠ず鐢熸垚鐨勪复鏃舵墭鐩樼爜 */
+  function handlePreGenerateSuccess(result: { id: number; tempCode: string }[]) {
+    Modal.success({
+      title: "棰勭敓鎴愪复鏃舵墭鐩樼爜鎴愬姛",
+      content: result.map((item) => item.tempCode).join("\n"),
+      centered: true,
+    });
   }
 
   /** 鎵爜杩芥函 */
@@ -47,9 +63,44 @@
     qrTraceQueryModalApi.open();
   }
 
-  /** 鏌ョ湅浜岀淮鐮侊紙琛屽唴棰勫~鐮佸�硷級 */
+  /** 鑾峰彇鎵樼洏鏄剧ず鐢ㄧ殑鐮佸�硷紙姝e紡鎵樼洏鐮佷紭鍏堬紝鍏舵涓存椂鎵樼洏鐮侊級 */
+  function getDisplayCode(row: MesProPalletApi.Pallet) {
+    return row.code || row.tempCode || "";
+  }
+
+  /** 鏌ョ湅浜岀淮鐮侊紙琛屽唴棰勫~鐮佸�硷紝涓存椂鎵樼洏鐢ㄤ复鏃舵墭鐩樼爜锛� */
   function handleViewQr(row: MesProPalletApi.Pallet) {
-    qrTraceQueryModalApi.setData({ code: row.code }).open();
+    qrTraceQueryModalApi.setData({ code: getDisplayCode(row) }).open();
+  }
+
+  /** 鑾峰彇鍕鹃�夌殑涓存椂鎵樼洏璁板綍 */
+  function getSelectedTempPallets(): MesProPalletApi.Pallet[] | undefined {
+    const records = [
+      ...(gridApi.grid.getCheckboxReserveRecords?.() ?? []),
+      ...(gridApi.grid.getCheckboxRecords?.() ?? []),
+    ] as MesProPalletApi.Pallet[];
+    const uniqueRecords = [
+      ...new Map(records.map((record) => [record.id, record])).values(),
+    ];
+    const tempRecords = uniqueRecords.filter((record) => !record.batchId);
+    if (uniqueRecords.length === 0) {
+      message.warning("璇疯嚦灏戝嬀閫変竴鏉℃墭鐩樼爜璁板綍");
+      return undefined;
+    }
+    if (tempRecords.length === 0) {
+      message.warning("鍕鹃�夌殑璁板綍鍧囧凡缁戝畾鎵规锛屾棤闇�缁戝畾");
+      return undefined;
+    }
+    return tempRecords;
+  }
+
+  /** 缁戝畾鎵规 */
+  function handleBindBatch() {
+    const records = getSelectedTempPallets();
+    if (!records) return;
+    bindBatchFormModalApi
+      .setData({ ids: records.map((record) => record.id!) })
+      .open();
   }
 
   /** 瀵煎嚭浜岀淮鐮� ZIP锛堟寜褰撳墠鏌ヨ鏉′欢鐨勬壒娆★級 */
@@ -63,10 +114,19 @@
     downloadFileFromBlobPart({ fileName: "鎵樼洏鐮佷簩缁寸爜.zip", source: data });
   }
 
+  /** 瀵煎嚭鍗曚釜鎵樼洏鐮佷簩缁寸爜 ZIP锛堟敮鎸佹湭缁戝畾鎵规鐨勪复鏃舵墭鐩橈級 */
+  async function handleExportQrById(row: MesProPalletApi.Pallet) {
+    const data = await exportPalletQrByIds([row.id!]);
+    downloadFileFromBlobPart({
+      fileName: `鎵樼洏鐮佷簩缁寸爜-${getDisplayCode(row)}.zip`,
+      source: data,
+    });
+  }
+
   /** 鍒犻櫎鎵樼洏鐮� */
   async function handleDelete(row: MesProPalletApi.Pallet) {
     await deletePallet(row.id!);
-    message.success($t("ui.actionMessage.deleteSuccess", [row.code]));
+    message.success($t("ui.actionMessage.deleteSuccess", [getDisplayCode(row)]));
     handleRefresh();
   }
 
@@ -81,6 +141,10 @@
       schema: useGridFormSchema(),
     },
     gridOptions: {
+      checkboxConfig: {
+        highlight: true,
+        reserve: true,
+      },
       columns: useGridColumns(),
       height: "auto",
       keepSource: true,
@@ -109,17 +173,24 @@
 
 <template>
   <Page auto-content-height>
-    <GenerateFormModal @success="handleRefresh" />
+    <GenerateFormModal @success="handlePreGenerateSuccess" />
+    <BindBatchFormModal @success="handleRefresh" />
     <QrTraceQueryModal />
     <Grid table-title="鎵樼洏鐮佸垪琛�">
       <template #toolbar-tools>
         <TableAction :actions="[
             {
-              label: '鎵归噺鐢熸垚',
+              label: '棰勭敓鎴愪簩缁寸爜',
               type: 'primary',
               icon: ACTION_ICON.ADD,
               auth: ['mes:pro-pallet:create'],
               onClick: handleCreate,
+            },
+            {
+              label: '缁戝畾鎵规',
+              icon: ACTION_ICON.EDIT,
+              auth: ['mes:pro-pallet:update'],
+              onClick: handleBindBatch,
             },
             {
               label: '鎵爜杩芥函',
@@ -142,6 +213,14 @@
             },
           ]" />
       </template>
+      <template #code="{ row }">
+        <span>{{ getDisplayCode(row) }}</span>
+        <Tag v-if="!row.code" color="warning">鏈粦瀹氭壒娆�</Tag>
+      </template>
+      <template #batchCode="{ row }">
+        <span v-if="row.batchCode">{{ row.batchCode }}</span>
+        <Tag v-else color="warning">鏈粦瀹氭壒娆�</Tag>
+      </template>
       <template #actions="{ row }">
         <TableAction :actions="[
             {
@@ -151,6 +230,13 @@
               onClick: handleViewQr.bind(null, row),
             },
             {
+              label: '瀵煎嚭浜岀淮鐮�',
+              type: 'link',
+              icon: ACTION_ICON.DOWNLOAD,
+              auth: ['mes:pro-pallet:export'],
+              onClick: handleExportQrById.bind(null, row),
+            },
+            {
               label: $t('common.delete'),
               type: 'link',
               danger: true,
@@ -158,7 +244,7 @@
               auth: ['mes:pro-pallet:delete'],
               ifShow: !row.bagCount,
               popConfirm: {
-                title: $t('ui.actionMessage.deleteConfirm', [row.code]),
+                title: $t('ui.actionMessage.deleteConfirm', [getDisplayCode(row)]),
                 confirm: handleDelete.bind(null, row),
               },
             },
diff --git a/src/views/mes/pro/pallet/modules/bind-batch.vue b/src/views/mes/pro/pallet/modules/bind-batch.vue
new file mode 100644
index 0000000..426168d
--- /dev/null
+++ b/src/views/mes/pro/pallet/modules/bind-batch.vue
@@ -0,0 +1,88 @@
+<script lang="ts" setup>
+  import type { VbenFormSchema } from "#/adapter/form";
+
+  import { useVbenModal } from "@vben/common-ui";
+  import { MesProBatchStatusEnum } from "@vben/constants";
+
+  import { message } from "ant-design-vue";
+
+  import { useVbenForm } from "#/adapter/form";
+  import { getBatchSimpleList } from "#/api/mes/pro/batch";
+  import { bindPalletBatch } from "#/api/mes/pro/pallet";
+  import { $t } from "#/locales";
+
+  defineOptions({ name: "MesProPalletBindBatch" });
+
+  interface ModalData {
+    ids: number[];
+  }
+
+  const emit = defineEmits(["success"]);
+
+  const [Form, formApi] = useVbenForm({
+    commonConfig: {
+      componentProps: {
+        class: "w-full",
+      },
+      labelWidth: 100,
+    },
+    layout: "horizontal",
+    schema: [],
+    showDefaultActions: false,
+  });
+
+  const [Modal, modalApi] = useVbenModal({
+    async onConfirm() {
+      const { valid } = await formApi.validate();
+      if (!valid) return;
+      const data = modalApi.getData<ModalData>();
+      const values = await formApi.getValues();
+      modalApi.lock();
+      try {
+        await bindPalletBatch({ batchId: values.batchId, ids: data.ids });
+        message.success($t("ui.actionMessage.operationSuccess"));
+        emit("success");
+        await modalApi.close();
+      } finally {
+        modalApi.unlock();
+      }
+    },
+    async onOpenChange(isOpen: boolean) {
+      if (!isOpen) return;
+      modalApi.lock();
+      try {
+        // 浠呭凡琛ュ綍姝e紡淇℃伅涓旂敓浜т腑鐨勬壒娆″厑璁哥粦瀹�
+        const batches = await getBatchSimpleList();
+        const options = batches
+          .filter(
+            (batch) =>
+              batch.status === MesProBatchStatusEnum.PRODUCING && batch.code,
+          )
+          .map((batch) => ({ label: batch.code!, value: batch.id! }));
+        const schema: VbenFormSchema[] = [
+          {
+            fieldName: "batchId",
+            label: "鐢熶骇鎵规",
+            component: "Select",
+            componentProps: {
+              options,
+              optionFilterProp: "label",
+              placeholder: "璇烽�夋嫨宸茶ˉ褰曚笖鐢熶骇涓殑鎵规",
+              showSearch: true,
+            },
+            rules: "selectRequired",
+          },
+        ];
+        await formApi.setState({ schema });
+      } finally {
+        modalApi.unlock();
+      }
+    },
+  });
+</script>
+
+<template>
+  <Modal title="鎵樼洏鐮佺粦瀹氱敓浜ф壒娆�" class="w-2/5">
+    <Form class="mx-4" />
+  </Modal>
+</template>
\ No newline at end of file
diff --git a/src/views/mes/pro/pallet/modules/generate-form.vue b/src/views/mes/pro/pallet/modules/generate-form.vue
index c34f952..e094e17 100644
--- a/src/views/mes/pro/pallet/modules/generate-form.vue
+++ b/src/views/mes/pro/pallet/modules/generate-form.vue
@@ -1,69 +1,16 @@
 <script lang="ts" setup>
   import type { VbenFormSchema } from "#/adapter/form";
-  import type { MesProPalletApi } from "#/api/mes/pro/pallet";
 
   import { useVbenModal } from "@vben/common-ui";
-  import { MesProBatchStatusEnum } from "@vben/constants";
 
   import { message } from "ant-design-vue";
 
   import { useVbenForm } from "#/adapter/form";
-  import { getBatchSimpleList } from "#/api/mes/pro/batch";
-  import { batchCreatePallet } from "#/api/mes/pro/pallet";
+  import { preGeneratePallet } from "#/api/mes/pro/pallet";
 
   defineOptions({ name: "MesProPalletGenerateForm" });
 
   const emit = defineEmits(["success"]);
-
-  /** 鏋勫缓琛ㄥ崟锛堟壒娆′笅鎷夐�夐」鐢卞閮ㄥ姞杞芥敞鍏ワ級 */
-  function buildSchema(batchOptions: { label: string; value: number }[]): VbenFormSchema[] {
-    return [
-      {
-        fieldName: "batchId",
-        label: "鐢熶骇鎵规",
-        component: "Select",
-        componentProps: {
-          options: batchOptions,
-          optionFilterProp: "label",
-          placeholder: "璇烽�夋嫨鐢熶骇涓殑鎵规",
-          showSearch: true,
-        },
-        rules: "selectRequired",
-      },
-      {
-        fieldName: "count",
-        label: "鐢熸垚鏁伴噺",
-        component: "InputNumber",
-        componentProps: {
-          class: "!w-full",
-          min: 1,
-          placeholder: "璇疯緭鍏ラ渶瑕佺敓鎴愮殑鎵樼洏鏁伴噺",
-          precision: 0,
-        },
-        rules: "required",
-      },
-      {
-        fieldName: "capacity",
-        label: "鍙琚嬫暟",
-        component: "InputNumber",
-        componentProps: {
-          class: "!w-full",
-          min: 1,
-          placeholder: "璇疯緭鍏ユ瘡鎵樼洏鍙琚嬫暟锛堣/鎵樼洏锛�",
-          precision: 0,
-        },
-      },
-      {
-        fieldName: "remark",
-        label: "澶囨敞",
-        component: "Textarea",
-        componentProps: {
-          placeholder: "璇疯緭鍏ュ娉�",
-          rows: 2,
-        },
-      },
-    ];
-  }
 
   const [Form, formApi] = useVbenForm({
     commonConfig: {
@@ -83,40 +30,62 @@
       if (!valid) return;
       modalApi.lock();
       try {
-        const values =
-          (await formApi.getValues()) as MesProPalletApi.BatchCreateParams;
-        const ids = await batchCreatePallet(values);
-        message.success(`宸叉垚鍔熺敓鎴� ${ids.length} 涓墭鐩樼爜`);
-        emit("success");
+        const values = await formApi.getValues();
+        const result = await preGeneratePallet({
+          count: values.count,
+          capacity: values.capacity,
+          remark: values.remark,
+        });
+        message.success(`宸茬敓鎴� ${result.length} 涓复鏃舵墭鐩樼爜`);
+        emit("success", result);
         await modalApi.close();
       } finally {
         modalApi.unlock();
       }
     },
-    async onOpenChange(isOpen: boolean) {
+    onOpenChange(isOpen: boolean) {
       if (!isOpen) return;
-      modalApi.lock();
-      try {
-        // 浠呯敓浜т腑鐨勬壒娆″厑璁哥敓鎴愭墭鐩樼爜
-        const batches = await getBatchSimpleList();
-        const options = batches
-          .filter(
-            (batch) => batch.status === MesProBatchStatusEnum.PRODUCING
-          )
-          .map((batch) => ({
-            label: batch.code!,
-            value: batch.id!,
-          }));
-        await formApi.setState({ schema: buildSchema(options) });
-      } finally {
-        modalApi.unlock();
-      }
+      const schema: VbenFormSchema[] = [
+        {
+          fieldName: "count",
+          label: "鐢熸垚鏁伴噺",
+          component: "InputNumber",
+          componentProps: {
+            class: "!w-full",
+            min: 1,
+            placeholder: "璇疯緭鍏ラ渶瑕佺敓鎴愮殑鎵樼洏鏁伴噺",
+            precision: 0,
+          },
+          rules: "required",
+        },
+        {
+          fieldName: "capacity",
+          label: "鍙琚嬫暟",
+          component: "InputNumber",
+          componentProps: {
+            class: "!w-full",
+            min: 1,
+            placeholder: "璇疯緭鍏ユ瘡鎵樼洏鍙琚嬫暟锛堣/鎵樼洏锛�",
+            precision: 0,
+          },
+        },
+        {
+          fieldName: "remark",
+          label: "澶囨敞",
+          component: "Textarea",
+          componentProps: {
+            placeholder: "璇疯緭鍏ュ娉�",
+            rows: 2,
+          },
+        },
+      ];
+      formApi.setState({ schema });
     },
   });
 </script>
 
 <template>
-  <Modal title="鎵归噺鐢熸垚鎵樼洏鐮�" class="w-2/5">
+  <Modal title="棰勭敓鎴愭墭鐩樹簩缁寸爜" class="w-2/5">
     <Form class="mx-4" />
   </Modal>
-</template>
+</template>
\ No newline at end of file

--
Gitblit v1.9.3