export interface GenerationStatusLike { status?: string | null; displayStatus?: string | null; pipelineStage?: string | null; shouldPoll?: boolean | null; } export type GenerationUiColor = 'default' | 'processing' | 'warning' | 'success' | 'error' | 'blue' | 'orange' | 'purple'; export interface GenerationUiState { status: string; displayStatus: string; pipelineStage: string; effectiveKey: string; label: string; color: GenerationUiColor; isActive: boolean; isSuccess: boolean; isFailure: boolean; isTerminal: boolean; } const ACTIVE_STATUS_KEYS = new Set(['pending', 'optimizing', 'generating']); const ACTIVE_PIPELINE_STAGES = new Set([ 'queued', 'preparing', 'creating_provider_task', 'provider_result_staged', 'waiting_remote', 'polling', 'result_ready', 'download_queued', 'downloading', 'retry_waiting', 'recovery_inconsistent', 'upscale_queued', 'upscale_processing', 'upscale_polling', 'upscale_downloading', 'upscale_finalizing', 'upscale_retry_waiting', ]); const SUCCESS_KEYS = new Set(['completed', 'done']); const FAILURE_KEYS = new Set(['failed', 'timeout', 'download_failed', 'upscale_failed']); const TERMINAL_KEYS = new Set([...SUCCESS_KEYS, ...FAILURE_KEYS, 'deleted']); const LABELS: Record = { pending: '待处理', optimizing: '提词处理中', prompt_optimized: '待生成', generating: '生成中', queued: '已入队', preparing: '准备中', creating_provider_task: '创建供应商任务', provider_result_staged: '供应商结果已暂存', waiting_remote: '等待供应商结果', polling: '轮询供应商结果', result_ready: '远程结果已就绪', download_queued: '下载已入队', downloading: '下载中', retry_waiting: '下载等待重试', recovery_inconsistent: '恢复证据异常', upscale_queued: '超分已入队', upscale_processing: '本地超分处理中', upscale_polling: '轮询远程超分', upscale_downloading: '下载超分结果', upscale_finalizing: '超分结果最终化', upscale_retry_waiting: '超分等待重试', completed: '已完成', done: '已完成', timeout: '任务超时', download_failed: '下载失败', upscale_failed: '超分失败', failed: '失败', deleted: '已删除', }; const COLOR_MAP: Record = { pending: 'default', optimizing: 'processing', prompt_optimized: 'blue', generating: 'warning', queued: 'processing', preparing: 'processing', creating_provider_task: 'processing', provider_result_staged: 'processing', waiting_remote: 'processing', polling: 'processing', result_ready: 'processing', download_queued: 'processing', downloading: 'processing', retry_waiting: 'orange', recovery_inconsistent: 'orange', upscale_queued: 'purple', upscale_processing: 'purple', upscale_polling: 'purple', upscale_downloading: 'purple', upscale_finalizing: 'purple', upscale_retry_waiting: 'orange', completed: 'success', done: 'success', failed: 'error', timeout: 'error', download_failed: 'error', upscale_failed: 'error', deleted: 'default', }; const normalize = (value?: string | null): string => String(value || '').trim().toLowerCase(); const firstMatching = (values: string[], keys: Set): string => values.find((item) => keys.has(item)) || ''; export const getGenerationStageLabel = (key?: string | null): string => { const normalized = normalize(key); return LABELS[normalized] || normalized || '未知状态'; }; export const getGenerationStatusColor = (key?: string | null): GenerationUiColor => { const normalized = normalize(key); return COLOR_MAP[normalized] || 'default'; }; export const resolveGenerationUiState = (value: GenerationStatusLike): GenerationUiState => { const status = normalize(value.status); const displayStatus = normalize(value.displayStatus); const pipelineStage = normalize(value.pipelineStage); const values = [pipelineStage, displayStatus, status].filter(Boolean); const failureKey = firstMatching(values, FAILURE_KEYS); const successKey = firstMatching(values, SUCCESS_KEYS); const deletedKey = firstMatching(values, new Set(['deleted'])); const effectiveKey = failureKey || deletedKey || successKey || pipelineStage || displayStatus || status || 'pending'; const isFailure = FAILURE_KEYS.has(effectiveKey); const isSuccess = SUCCESS_KEYS.has(effectiveKey); const isActive = typeof value.shouldPoll === 'boolean' ? value.shouldPoll : (!isFailure && !isSuccess && effectiveKey !== 'deleted' && (ACTIVE_PIPELINE_STAGES.has(pipelineStage) || ACTIVE_STATUS_KEYS.has(status) || ACTIVE_STATUS_KEYS.has(displayStatus))); return { status, displayStatus, pipelineStage, effectiveKey, label: getGenerationStageLabel(effectiveKey), color: getGenerationStatusColor(effectiveKey), isActive, isSuccess, isFailure, isTerminal: TERMINAL_KEYS.has(effectiveKey), }; }; export const isGenerationActive = (value: GenerationStatusLike): boolean => resolveGenerationUiState(value).isActive; export const isGenerationSuccess = (value: GenerationStatusLike): boolean => resolveGenerationUiState(value).isSuccess; export const isGenerationFailure = (value: GenerationStatusLike): boolean => resolveGenerationUiState(value).isFailure; export const isGenerationTerminal = (value: GenerationStatusLike): boolean => resolveGenerationUiState(value).isTerminal;