diff --git a/src/frontend/src/store.ts b/src/frontend/src/store.ts index b73a64b..0479b6b 100644 --- a/src/frontend/src/store.ts +++ b/src/frontend/src/store.ts @@ -674,3 +674,67 @@ export function timeAgo(iso: string | undefined): string { return ''; } } + +// ── SSE 实时事件监听 ── + +let _es: EventSource | null = null; + +export function startSSE() { + if (_es) return; + try { + _es = new EventSource('/api/events'); + _es.addEventListener('task_updated', (e: MessageEvent) => { + try { + const data = JSON.parse(e.data); + const s = useStore.getState(); + const tasks = [...s.v2tasks]; + const idx = tasks.findIndex((t: any) => t.id === data.task_id); + if (idx >= 0) { + tasks[idx] = { ...tasks[idx], status: data.new_status }; + useStore.setState({ v2tasks: tasks }); + } else { + s.loadV2Tasks(); + } + } catch { /* ignore */ } + }); + _es.addEventListener('task_created', () => { + useStore.getState().loadV2Tasks(); + }); + _es.addEventListener('task_completed', (e: MessageEvent) => { + try { + const data = JSON.parse(e.data); + const s = useStore.getState(); + const tasks = [...s.v2tasks]; + const idx = tasks.findIndex((t: any) => t.id === data.task_id); + if (idx >= 0) { + tasks[idx] = { ...tasks[idx], status: 'done' }; + useStore.setState({ v2tasks: tasks }); + } + } catch { /* ignore */ } + }); + _es.addEventListener('task_failed', (e: MessageEvent) => { + try { + const data = JSON.parse(e.data); + const s = useStore.getState(); + const tasks = [...s.v2tasks]; + const idx = tasks.findIndex((t: any) => t.id === data.task_id); + if (idx >= 0) { + tasks[idx] = { ...tasks[idx], status: 'failed' }; + useStore.setState({ v2tasks: tasks }); + } + } catch { /* ignore */ } + }); + _es.onerror = () => { + _es?.close(); + _es = null; + setTimeout(startSSE, 3000); + }; + } catch { /* ignore */ } +} + +export function stopSSE() { + if (_es) { + _es.close(); + _es = null; + } +}