import type { Asset, PipelineProgress, PipelineStage, Project, Task } from './types' const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)) const randomDelay = () => delay(300 + Math.random() * 500) // Mock 数据 const MOCK_PROJECT: Project = { id: 'proj-default', name: '我的工程', style: { kvPairs: { artStyle: 'pixel', palette: 'warm', lineWeight: 'thin', scene: 'forest', lighting: 'bright', mood: 'cheerful', }, }, createdAt: '2026-05-20T10:00:00Z', } const MOCK_TASKS: Task[] = [ { id: 'task-001', projectId: 'proj-default', prompt: '一个拿剑的小人', assetType: 'sprite', status: 'completed', progress: 100, createdAt: '2026-05-24T09:00:00Z', updatedAt: '2026-05-24T09:02:00Z', }, { id: 'task-002', projectId: 'proj-default', prompt: '森林背景', assetType: 'background', status: 'failed', error: '生成超时', createdAt: '2026-05-24T08:00:00Z', updatedAt: '2026-05-24T08:10:00Z', }, { id: 'task-003', projectId: 'proj-default', prompt: '魔法药水瓶', assetType: 'ui', status: 'completed', progress: 100, createdAt: '2026-05-23T15:00:00Z', updatedAt: '2026-05-23T15:03:00Z', }, ] const MOCK_ASSETS: Asset[] = [ { id: 'asset-001', key: 'generation/proj-001/task-001/0.png', url: 'https://placehold.co/256x256/e94560/1a1a2e?text=Sprite', format: 'png', width: 256, height: 256, metadata: { frameWidth: 64, frameHeight: 64, frameCount: 16, directions: 4, }, }, ] // Mock API 函数 export async function mockGetProject(_id: string): Promise { await randomDelay() return { ...MOCK_PROJECT } } export async function mockGetStyle( _projectId: string ): Promise> { await randomDelay() return { ...MOCK_PROJECT.style.kvPairs } } export async function mockSaveStyle( _projectId: string, _kvPairs: Record ): Promise { await randomDelay() } export async function mockGetTasks(_projectId: string): Promise { await randomDelay() return MOCK_TASKS.map(t => ({ ...t })) } export async function mockGetTask(taskId: string): Promise { await randomDelay() const task = MOCK_TASKS.find(t => t.id === taskId) if (!task) throw new Error('任务不存在') return { ...task } } export async function mockGetAssets(_taskId: string): Promise { await randomDelay() return MOCK_ASSETS.map(a => ({ ...a })) } export async function mockSubmitGenerate( _projectId: string, prompt: string, assetType: string ): Promise { await delay(500) const taskId = `task-${Date.now()}` MOCK_TASKS.unshift({ id: taskId, projectId: _projectId, prompt, assetType, status: 'pending', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }) return taskId } // 模拟 WebSocket 管线进度 const STAGES: PipelineStage[] = [ 'prompt_builder', 'asset_generator', 'quality_supervisor', 'format_adapter', ] const STAGE_LABELS: Record = { prompt_builder: '提示词构建', asset_generator: '素材生成', quality_supervisor: '质量检查', format_adapter: '格式转换', } export { STAGE_LABELS } export function createMockWebSocket( _taskId: string, onProgress: (msg: PipelineProgress) => void, onComplete: (assets: Asset[]) => void, _onError?: (error: string) => void ): () => void { let stageIndex = 0 let tick = 0 let retryCount = 0 const maxRetries = 1 let cancelled = false const interval = setInterval(() => { if (cancelled) return const stage = STAGES[stageIndex] const stageProgress = (tick % 3) * 50 // 0, 50, 100 // 质检阶段有概率重试 if ( stage === 'quality_supervisor' && stageProgress === 100 && retryCount < maxRetries && Math.random() < 0.3 ) { onProgress({ stage: 'quality_supervisor', status: 'failed', progress: 100, retryCount: retryCount + 1, rejectReason: '风格一致性不足', }) retryCount++ stageIndex = 0 tick = 0 return } const isLastTickOfStage = stageProgress === 100 const isLastStage = stageIndex === STAGES.length - 1 if (isLastTickOfStage && isLastStage) { // 管线完成 onProgress({ stage: 'format_adapter', status: 'completed', progress: 100, result: { assets: MOCK_ASSETS }, }) onComplete(MOCK_ASSETS) clearInterval(interval) return } onProgress({ stage, status: isLastTickOfStage ? 'completed' : 'running', progress: stageProgress, retryCount: retryCount > 0 ? retryCount : undefined, }) tick++ if (isLastTickOfStage) { stageIndex++ tick = 0 } }, 1000) return () => { cancelled = true clearInterval(interval) } }