| | |
| | | <script lang="ts" setup> |
| | | import type { VbenFormSchema } from "#/adapter/form"; |
| | | |
| | | import { markRaw } from "vue"; |
| | | import { markRaw, ref } from "vue"; |
| | | |
| | | 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 { generateRawBagCodes } from "#/api/mes/pro/bagCode"; |
| | | import { MdmItemSelect } from "#/views/basicData/mdm/components"; |
| | | |
| | | import { isFinalTaskStatus, useGenerateTask } from "./use-generate-task"; |
| | | |
| | | defineOptions({ name: "MesProBagCodeRawGenerateForm" }); |
| | | |
| | | const emit = defineEmits(["success"]); |
| | | |
| | | /** 幂等键:打开弹窗时生成,网络重试复用;失败后重新生成 */ |
| | | const requestId = ref(""); |
| | | |
| | | function newRequestId() { |
| | | return `${Date.now()}-${Math.random().toString(36).slice(2)}-${Math.random() |
| | | .toString(36) |
| | | .slice(2)}`; |
| | | } |
| | | |
| | | const schema: VbenFormSchema[] = [ |
| | | { |
| | |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) return; |
| | | if (task.value && !isFinalTaskStatus(task.value.status)) return; |
| | | modalApi.lock(); |
| | | let asyncStarted = false; |
| | | try { |
| | | const values = await formApi.getValues(); |
| | | const result = await generateRawBagCodes({ |
| | | itemId: values.itemId, |
| | | count: values.count, |
| | | remark: values.remark, |
| | | requestId: requestId.value, |
| | | }); |
| | | 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} 条原始袋码`); |
| | | emit("success"); |
| | | await modalApi.close(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | if (!asyncStarted) modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) return; |
| | | if (!isOpen) { |
| | | stopGenerateTaskPolling(); |
| | | return; |
| | | } |
| | | resetGenerateTask(); |
| | | requestId.value = newRequestId(); |
| | | await formApi.setValues({ |
| | | itemId: undefined, |
| | | count: undefined, |
| | |
| | | }); |
| | | }, |
| | | }); |
| | | |
| | | 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 class="mx-4 mb-2 rounded bg-gray-50 px-3 py-2 text-sm text-gray-500"> |
| | | 原始袋码仅需选择品种并输入数量,不换算计量单位类型、不生成托盘;后续可正常录入批次或绑定托盘 |
| | | </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 class="mx-4 mb-2 rounded bg-gray-50 px-3 py-2 text-sm text-gray-500"> |
| | | 原始袋码仅需选择品种并输入数量,不换算计量单位类型、不生成托盘;后续可正常录入批次或绑定托盘 |
| | | </div> |
| | | </template> |
| | | </Modal> |
| | | </template> |