import type { MesProBagCodeApi } from '#/api/mes/pro/bagCode';
|
|
import { onBeforeUnmount, ref } from 'vue';
|
|
import { message } from 'ant-design-vue';
|
|
import {
|
cancelBagCodeGenerateTask,
|
getBagCodeGenerateTask,
|
} from '#/api/mes/pro/bagCode';
|
|
/** 弹窗最小接口,避免依赖内部 ModalApi 类型 */
|
interface GenerateModalApi {
|
close: () => Promise<void>;
|
setState: (state: {
|
showCancelButton?: boolean;
|
showConfirmButton?: boolean;
|
}) => unknown;
|
}
|
|
interface GenerateTaskCallbacks {
|
/** 生成成功(状态 30),调用方刷新列表 */
|
onSuccess: () => void;
|
/** 生成失败(状态 50),调用方更换幂等键后允许重新提交 */
|
onFailed?: () => void;
|
}
|
|
/** 终态:已完成 / 已取消 / 已失败 */
|
const FINAL_STATUSES = new Set([30, 40, 50]);
|
|
export function isFinalTaskStatus(status?: number) {
|
return status !== undefined && FINAL_STATUSES.has(status);
|
}
|
|
/**
|
* 大批量袋码后台生成:轮询进度、取消任务,并把弹窗按钮切换为进度展示态。
|
*/
|
export function useGenerateTask(
|
modalApi: GenerateModalApi,
|
callbacks: GenerateTaskCallbacks,
|
) {
|
const task = ref<MesProBagCodeApi.GenerateTask>();
|
const canceling = ref(false);
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
function stopPolling() {
|
if (timer) clearTimeout(timer);
|
timer = undefined;
|
}
|
|
function restoreButtons() {
|
modalApi.setState({ showConfirmButton: true, showCancelButton: true });
|
}
|
|
/** 重置到可编辑态:关闭弹窗、重新打开、失败重试前调用 */
|
function reset() {
|
stopPolling();
|
task.value = undefined;
|
canceling.value = false;
|
restoreButtons();
|
}
|
|
/** 进入进度展示态:隐藏提交/取消按钮,进度区自行提供取消操作 */
|
function start(initial: MesProBagCodeApi.GenerateTask) {
|
stopPolling();
|
task.value = initial;
|
modalApi.setState({ showConfirmButton: false, showCancelButton: false });
|
void refresh();
|
}
|
|
async function refresh() {
|
if (!task.value) return;
|
stopPolling();
|
try {
|
const current = await getBagCodeGenerateTask(task.value.id);
|
task.value = current;
|
if (isFinalTaskStatus(current.status)) {
|
finish(current);
|
return;
|
}
|
} catch {
|
// 一次查询失败不终止轮询,避免网络抖动把进度卡死
|
}
|
timer = setTimeout(refresh, 2000);
|
}
|
|
function finish(current: MesProBagCodeApi.GenerateTask) {
|
if (current.status === 30) {
|
message.success(
|
`生成完成:共 ${current.totalCount ?? 0} 条袋码` +
|
(current.palletCount
|
? `,并自动生成 ${current.palletCount} 个托盘`
|
: ''),
|
);
|
callbacks.onSuccess();
|
void modalApi.close();
|
return;
|
}
|
if (current.status === 40) {
|
message.info('生成任务已取消,已生成的数据已清理');
|
void modalApi.close();
|
return;
|
}
|
// 失败:回到可编辑态,由调用方更换 requestId 后重新提交
|
message.error(current.errorMsg ?? '生成失败,请重新提交');
|
task.value = undefined;
|
restoreButtons();
|
callbacks.onFailed?.();
|
}
|
|
async function cancel() {
|
if (!task.value || canceling.value) return;
|
canceling.value = true;
|
try {
|
await cancelBagCodeGenerateTask(task.value.id);
|
message.info('已申请取消,正在停止并清理已生成数据');
|
} catch {
|
message.error('取消生成失败,请稍后重试');
|
} finally {
|
canceling.value = false;
|
}
|
}
|
|
onBeforeUnmount(stopPolling);
|
|
return {
|
task,
|
canceling,
|
cancel,
|
reset,
|
stopPolling,
|
start,
|
};
|
}
|