Files
sanguo_vnpy_v2/frontend/src/composables/useTask.ts
T
claude_dev 80d7f58589 feat(frontend): S1 回测核心页(新建/进度/结果 + ECharts 图表)
- api/strategy.ts、api/backtest.ts(含类型)
- 回测-新建(策略下拉+动态参数表单+日期+提交)
- useTask 组合式(轮询+WS 实时阶段)+ 进度页
- 结果页:统计全表 + 资金曲线 + 每日盈亏(红涨绿跌) + 成交表 + K线买卖点
- build 通过;result 接口扩 symbol/start/end 供 K线调用
2026-07-07 06:13:10 +08:00

56 lines
1.5 KiB
TypeScript

import { ref, onUnmounted } from 'vue'
import { getStatus } from '@/api/backtest'
import { useAuthStore } from '@/stores/auth'
export type TaskState = 'pending' | 'running' | 'done' | 'failed' | 'unknown'
/**
* Track a task's status + stage via polling (2s) and WebSocket (real-time).
* Auto-stops on unmount.
*/
export function useTask(taskId: string) {
const status = ref<TaskState>('unknown')
const stage = ref('')
let timer: ReturnType<typeof setInterval> | null = null
let ws: WebSocket | null = null
async function poll(): Promise<void> {
try {
const s = await getStatus(taskId)
status.value = s.status as TaskState
stage.value = s.stage
} catch {
/* transient — keep last known state */
}
}
function start(): void {
poll()
timer = setInterval(poll, 2000)
const proto = window.location.protocol === 'https:' ? 'wss' : 'ws'
const auth = useAuthStore()
const url = `${proto}://${window.location.host}/api/v1/ws/task/${taskId}?token=${auth.token}`
try {
ws = new WebSocket(url)
ws.onmessage = (ev) => {
try {
const msg = JSON.parse(ev.data)
if (msg.stage) stage.value = msg.stage
if (msg.status) status.value = msg.status
} catch {
/* ignore non-JSON keepalive frames */
}
}
} catch {
/* WS optional — polling covers it */
}
}
onUnmounted(() => {
if (timer) clearInterval(timer)
if (ws) ws.close()
})
return { status, stage, start }
}