From 212ad6426def84d85d9b83931bffb900b1b5b12e Mon Sep 17 00:00:00 2001 From: claude_dev Date: Tue, 7 Jul 2026 06:28:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(s2):=20=E6=8A=95=E7=A0=94=E6=A0=B8?= =?UTF-8?q?=E5=BF=83=E7=AB=AF=E5=88=B0=E7=AB=AF=E8=B7=91=E9=80=9A=EF=BC=88?= =?UTF-8?q?IC=20=E8=A1=A8=20+=20tears=20=E6=8A=A5=E5=91=8A=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Task 加 raw_result 字段;orchestrator get_raw_result(内存存 FactorReport) - 路由 /factor/list、/task/{id}/ic-summary、/task/{id}/report/{factor}(query token 给 iframe) - analyzer cfg=None 时加载 data_platform.yaml(修 API 路径 read_db_daily 崩) - get_status 返回 error_msg(调试+前端 failed 展示) - 前端 投研-新建(多因子/多标的/日期)+ 结果页(IC 表 + tears iframe) - factor 冒烟通过:ma5 → IC 1D/5D/10D 真实数据 --- frontend/src/api/factor.ts | 35 ++++++++++ frontend/src/router/index.ts | 1 + frontend/src/views/backtest/Progress.vue | 5 +- frontend/src/views/factor/New.vue | 82 +++++++++++++++++++++- frontend/src/views/factor/Result.vue | 89 +++++++++++++++++++++++- sanguo_api/routes.py | 50 ++++++++++++- sanguo_factor/analyzer.py | 6 ++ sanguo_orchestrator/runner.py | 10 +++ sanguo_orchestrator/task.py | 2 + scripts/smoke_phase3b_factor.py | 71 +++++++++++++++++++ tests/api/test_factor_routes.py | 73 +++++++++++++++++++ 11 files changed, 416 insertions(+), 8 deletions(-) create mode 100644 frontend/src/api/factor.ts create mode 100644 scripts/smoke_phase3b_factor.py create mode 100644 tests/api/test_factor_routes.py diff --git a/frontend/src/api/factor.ts b/frontend/src/api/factor.ts new file mode 100644 index 0000000..b3e403e --- /dev/null +++ b/frontend/src/api/factor.ts @@ -0,0 +1,35 @@ +import { apiClient } from './client' +import { useAuthStore } from '@/stores/auth' + +export interface FactorItem { + name: string + category: string +} + +export interface FactorSubmit { + symbols: string[] + factor_names: string[] + start: string + end: string +} + +export async function getFactors(): Promise { + const { data } = await apiClient.get<{ factors: FactorItem[] }>('/factor/list') + return data.factors +} + +export async function submitFactor(req: FactorSubmit): Promise { + const { data } = await apiClient.post<{ task_id: string }>('/factor/analyze', req) + return data.task_id +} + +export async function getIcSummary(taskId: string): Promise> { + const { data } = await apiClient.get<{ ic_summary: Record }>(`/task/${taskId}/ic-summary`) + return data.ic_summary +} + +/** Report URL with token in query (iframe can't set Authorization header). */ +export function reportUrl(taskId: string, factor: string): string { + const auth = useAuthStore() + return `/api/v1/task/${taskId}/report/${factor}?token=${encodeURIComponent(auth.token ?? '')}` +} diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index de0e552..91bc0cb 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -12,6 +12,7 @@ const routes: RouteRecordRaw[] = [ { path: 'backtest/progress/:id', name: 'bt-progress', component: () => import('@/views/backtest/Progress.vue') }, { path: 'backtest/result/:id', name: 'bt-result', component: () => import('@/views/backtest/Result.vue') }, { path: 'factor/new', name: 'fc-new', component: () => import('@/views/factor/New.vue') }, + { path: 'factor/progress/:id', name: 'fc-progress', component: () => import('@/views/backtest/Progress.vue') }, { path: 'factor/result/:id', name: 'fc-result', component: () => import('@/views/factor/Result.vue') }, ], }, diff --git a/frontend/src/views/backtest/Progress.vue b/frontend/src/views/backtest/Progress.vue index 90605f9..fce622a 100644 --- a/frontend/src/views/backtest/Progress.vue +++ b/frontend/src/views/backtest/Progress.vue @@ -11,7 +11,10 @@ const { status, stage, start } = useTask(taskId) start() watch(status, (s) => { - if (s === 'done') router.push(`/backtest/result/${taskId}`) + if (s === 'done') { + const base = route.path.startsWith('/factor') ? '/factor' : '/backtest' + router.push(`${base}/result/${taskId}`) + } }) function pct(): number { diff --git a/frontend/src/views/factor/New.vue b/frontend/src/views/factor/New.vue index 50ae65b..1c0e5e4 100644 --- a/frontend/src/views/factor/New.vue +++ b/frontend/src/views/factor/New.vue @@ -1,4 +1,82 @@ - + + diff --git a/frontend/src/views/factor/Result.vue b/frontend/src/views/factor/Result.vue index 9c9daf1..274be58 100644 --- a/frontend/src/views/factor/Result.vue +++ b/frontend/src/views/factor/Result.vue @@ -1,4 +1,89 @@ - + +