From 12250a63a8f65a37451fd49392a3cc90facbceaa Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 19 十月 2026 17:31:29 +0800
Subject: [PATCH] feat(bagCode): 添加袋码批量生成后台任务支持

---
 src/views/mes/pro/bagCode/modules/generate-form.vue |  111 +++++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 98 insertions(+), 13 deletions(-)

diff --git a/src/views/mes/pro/bagCode/modules/generate-form.vue b/src/views/mes/pro/bagCode/modules/generate-form.vue
index a9bf722..5613a5d 100644
--- a/src/views/mes/pro/bagCode/modules/generate-form.vue
+++ b/src/views/mes/pro/bagCode/modules/generate-form.vue
@@ -7,12 +7,14 @@
 
   import { useVbenModal } from "@vben/common-ui";
 
-  import { message } from "ant-design-vue";
+  import { Button, message, Progress } from "ant-design-vue";
 
   import { useVbenForm } from "#/adapter/form";
   import { generateBagCodes } from "#/api/mes/pro/bagCode";
   import { getUnit } from "#/api/mdm/unit";
   import { MdmItemSelect } from "#/views/basicData/mdm/components";
+
+  import { isFinalTaskStatus, useGenerateTask } from "./use-generate-task";
 
   defineOptions({ name: "MesProBagCodeGenerateForm" });
 
@@ -25,6 +27,15 @@
   const unitTypeError = ref(false);
   const palletCountVal = ref<number | null>(null);
   const bagCountVal = ref<number | null>(null);
+
+  /** 骞傜瓑閿細鎵撳紑寮圭獥鏃剁敓鎴愶紝缃戠粶閲嶈瘯澶嶇敤锛涘け璐ュ悗閲嶆柊鐢熸垚 */
+  const requestId = ref("");
+
+  function newRequestId() {
+    return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random()
+      .toString(36)
+      .slice(2)}`;
+  }
 
   /** 鎹㈢畻/閰嶇疆鎻愮ず鏂囨 */
   const tipText = computed(() => {
@@ -155,17 +166,20 @@
     async onConfirm() {
       const { valid } = await formApi.validate();
       if (!valid) return;
+      if (task.value && !isFinalTaskStatus(task.value.status)) return;
       if (unitTypeError.value) {
         message.warning(tipText.value);
         return;
       }
       modalApi.lock();
+      let asyncStarted = false;
       try {
         const values =
           (await formApi.getValues()) as MesProBagCodeApi.GenerateParams;
         const data: MesProBagCodeApi.GenerateParams = {
           itemId: values.itemId,
           remark: values.remark,
+          requestId: requestId.value,
         };
         if (isTon.value) {
           data.bagCount = values.bagCount;
@@ -173,22 +187,43 @@
           data.palletCount = values.palletCount;
         }
         const result = await generateBagCodes(data);
+        if (result.async && result.taskId) {
+          asyncStarted = true;
+          modalApi.unlock();
+          // 澶ф壒閲忓凡杞悗鍙帮細淇濇寔寮圭獥鎵撳紑锛屽睍绀鸿繘搴﹀苟杞
+          startGenerateTask({
+            id: result.taskId,
+            status: 10,
+            statusName: "鎺掗槦涓�",
+            progress: 0,
+            totalCount: result.totalCount,
+            finishedCount: 0,
+            palletCount: result.palletCount,
+            uuid: result.uuid,
+          });
+          return;
+        }
         message.success(
           `宸叉垚鍔熺敓鎴� ${result.totalCount} 鏉¤鐮乣 +
-            (result.palletIds?.length
-              ? `锛屽苟鑷姩鐢熸垚 ${result.palletIds.length} 涓墭鐩榒
+            (result.palletCount
+              ? `锛屽苟鑷姩鐢熸垚 ${result.palletCount} 涓墭鐩榒
               : ""),
         );
         emit("success");
         await modalApi.close();
       } finally {
-        modalApi.unlock();
+        if (!asyncStarted) modalApi.unlock();
       }
     },
     async onOpenChange(isOpen: boolean) {
-      if (!isOpen) return;
+      if (!isOpen) {
+        stopGenerateTaskPolling();
+        return;
+      }
       modalApi.lock();
       try {
+        resetGenerateTask();
+        requestId.value = newRequestId();
         unitType.value = "";
         bagsPerPallet.value = null;
         isTon.value = false;
@@ -207,17 +242,67 @@
       }
     },
   });
+
+  const {
+    task,
+    canceling: generateTaskCanceling,
+    cancel: cancelGenerateTask,
+    reset: resetGenerateTask,
+    stopPolling: stopGenerateTaskPolling,
+    start: startGenerateTask,
+  } = useGenerateTask(modalApi, {
+    onSuccess: () => emit("success"),
+    onFailed: () => {
+      // 澶辫触鍚庢崲鏂扮殑骞傜瓑閿紝鍏佽鐢ㄦ埛鐩存帴閲嶆柊鎻愪氦
+      requestId.value = newRequestId();
+    },
+  });
 </script>
 
 <template>
   <Modal title="鐢熸垚琚嬬爜鏁版嵁鍖�" class="w-2/5">
-    <Form class="mx-4" />
-    <div
-      v-if="tipText"
-      class="mx-4 mb-2 rounded bg-gray-50 px-3 py-2 text-sm"
-      :class="unitTypeError ? 'text-red-500' : 'text-gray-500'"
-    >
-      {{ tipText }}
-    </div>
+    <template v-if="task">
+      <div class="mx-4 mb-2">
+        <p class="mb-1 text-sm">
+          浠诲姟 #{{ task.id }} 路 {{ task.statusName }}
+        </p>
+        <p class="mb-2 text-sm text-gray-500">
+          宸茬敓鎴� {{ task.finishedCount ?? 0 }} / {{ task.totalCount ?? 0 }} 鏉�
+        </p>
+        <Progress
+          :percent="task.progress ?? 0"
+          :status="
+            task.status === 50
+              ? 'exception'
+              : task.status === 30
+                ? 'success'
+                : 'active'
+          "
+        />
+        <p v-if="task.errorMsg" class="mt-2 text-sm text-red-500">
+          {{ task.errorMsg }}
+        </p>
+        <div class="mt-4 flex justify-end">
+          <Button
+            danger
+            size="small"
+            :loading="generateTaskCanceling"
+            @click="cancelGenerateTask"
+          >
+            鍙栨秷鐢熸垚
+          </Button>
+        </div>
+      </div>
+    </template>
+    <template v-else>
+      <Form class="mx-4" />
+      <div
+        v-if="tipText"
+        class="mx-4 mb-2 rounded bg-gray-50 px-3 py-2 text-sm"
+        :class="unitTypeError ? 'text-red-500' : 'text-gray-500'"
+      >
+        {{ tipText }}
+      </div>
+    </template>
   </Modal>
 </template>

--
Gitblit v1.9.3