feat(task-logs): 实现任务日志 SSE 实时推送
实现任务日志 SSE 实时推送功能,解决前端无法流式输出日志的问题 变更内容: - 后端:新增 /task-logs/stream SSE 端点,支持实时日志推送 - 后端:实现 2 秒轮询间隔检测新日志,支持心跳机制 - 后端:支持通过 query 参数 access_token 传递 JWT 认证 - 前端:新增 createTaskLogStream 函数封装 EventSource - 前端:修改 TaskCenter.vue 集成 SSE,支持实时更新和自动滚动 - 前端:添加流式连接状态指示器 关联 commit: - 实现后端 SSE Stream 方法 - 注册 SSE 路由 - 实现前端 SSE 客户端 - 集成 SSE 到任务中心页面
This commit is contained in:
@@ -79,3 +79,49 @@ function parseResponseBody(text: string) {
|
||||
return { error: text }
|
||||
}
|
||||
}
|
||||
|
||||
export interface TaskLogStreamCallbacks {
|
||||
onInit?: (lines: TaskLogLine[]) => void
|
||||
onUpdate?: (lines: TaskLogLine[]) => void
|
||||
onFinished?: () => void
|
||||
onError?: (error: string) => void
|
||||
}
|
||||
|
||||
export function createTaskLogStream(taskId: string, callbacks: TaskLogStreamCallbacks): EventSource {
|
||||
const token = getToken()
|
||||
const url = `/auth/api/v1/task-logs/stream?task_id=${encodeURIComponent(taskId)}&access_token=${encodeURIComponent(token || '')}`
|
||||
|
||||
const es = new EventSource(url)
|
||||
|
||||
es.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data)
|
||||
switch (data.type) {
|
||||
case 'init':
|
||||
callbacks.onInit?.(Array.isArray(data.lines) ? data.lines : [])
|
||||
break
|
||||
case 'update':
|
||||
callbacks.onUpdate?.(Array.isArray(data.lines) ? data.lines : [])
|
||||
break
|
||||
case 'finished':
|
||||
callbacks.onFinished?.()
|
||||
es.close()
|
||||
break
|
||||
case 'error':
|
||||
callbacks.onError?.(data.error || 'Unknown error')
|
||||
break
|
||||
}
|
||||
} catch {
|
||||
// ignore parse errors for heartbeat etc.
|
||||
}
|
||||
}
|
||||
|
||||
es.onerror = () => {
|
||||
// EventSource will auto-reconnect, but we report connection errors
|
||||
if (es.readyState === EventSource.CLOSED) {
|
||||
callbacks.onError?.('Connection closed')
|
||||
}
|
||||
}
|
||||
|
||||
return es
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user