import { ApiResponse } from './common'; import { showQueueNotification } from '../components/QueueBox/QueueNotification2'; import { notification } from 'antd'; /** 队列状态枚举 */ export enum QueueStatus { WAIT = 'wait', // 排队等待中 READY = 'ready', // 可以开始处理 PROCESS = 'process' // 处理中 } /** 队列响应数据接口 */ export interface QueueResponseData { status: QueueStatus; position?: number; queue_length?: number; waiting?: number; message?: string; } /** 队列响应接口 */ export interface QueueResponse extends ApiResponse { code: number; message: string; data: QueueResponseData; } /** * 处理API轮询的配置选项 */ interface PollConfig { /** 轮询间隔(ms), 默认10000ms */ interval?: number; /** 最大轮询次数, 默认120次(20分钟) */ maxAttempts?: number; /** 轮询成功后的回调 */ onSuccess?: (data: any) => void; /** 轮询失败后的回调 */ onError?: (error: Error) => void; /** 每次轮询时的回调 */ onPolling?: (data: QueueResponseData) => void; /** 取消轮询时的回调 */ onCancel?: () => void; } // 用于存储取消函数的映射 const cancelTokens = new Map void>(); /** * 统一的队列API调用封装 */ export async function withQueuePolling( apiCall: (params: T) => Promise, params: T, config: PollConfig = {} ): Promise { const { interval = 10000, maxAttempts = 120, onSuccess, onError, onPolling, onCancel } = config; let attempts = 0; let lastNotificationPosition: number | undefined; let isCancelled = false; // 生成唯一的轮询ID const pollId = Math.random().toString(36).substring(7); // 创建取消函数 const cancel = () => { isCancelled = true; notification.destroy(); // 关闭通知 onCancel?.(); cancelTokens.delete(pollId); }; // 存储取消函数 cancelTokens.set(pollId, cancel); const poll = async (): Promise => { try { if (isCancelled) { throw new Error('操作已取消'); } const response = await apiCall(params); // 处理队列状态 if (response.code === 202 && (response.data.status === QueueStatus.WAIT || response.data.status === QueueStatus.PROCESS)) { attempts++; // 获取队列位置和等待时间 const { position, waiting, status } = response.data; // 如果位置发生变化,更新通知 if ((position !== lastNotificationPosition || status === QueueStatus.PROCESS) && position !== undefined && waiting !== undefined) { showQueueNotification(position, waiting, status, cancel); lastNotificationPosition = position; } // 调用轮询回调 onPolling?.(response.data); // 检查是否达到最大尝试次数 if (attempts >= maxAttempts) { notification.destroy(); // 关闭通知 throw new Error('超过最大轮询次数限制'); } // 继续轮询 await new Promise(resolve => setTimeout(resolve, interval)); return poll(); } // 如果状态为ready,结束轮询 if (response.code !== 202 && response.data) { notification.destroy(); // 关闭通知 onSuccess?.(response.data); return response; } notification.destroy(); // 关闭通知 return response; } catch (error) { notification.destroy(); // 关闭通知 if (error instanceof Error) { onError?.(error); } throw error; } finally { cancelTokens.delete(pollId); } }; return poll(); } /** * 取消指定的轮询 */ export function cancelPolling(pollId: string) { const cancel = cancelTokens.get(pollId); if (cancel) { cancel(); } } /** * 取消所有轮询 */ export function cancelAllPolling() { // 将 Map 转换为数组后再遍历 Array.from(cancelTokens.values()).forEach(cancel => cancel()); cancelTokens.clear(); }