From b2ee9f73411e3923c06479a19018997c9af53030 Mon Sep 17 00:00:00 2001 From: claude_dev Date: Sat, 11 Jul 2026 16:20:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=B7=B1=E9=93=BESPA=20fallback(?= =?UTF-8?q?=E5=88=B7=E6=96=B0/=E6=94=B6=E8=97=8F=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E9=A1=B5=E4=B8=8D=E5=86=8D404)=20+=20=E6=96=B0=E5=BB=BA?= =?UTF-8?q?=E5=9B=9E=E6=B5=8B=E5=8A=A0=E5=9F=BA=E5=87=86=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E5=99=A8(hs300/zz500)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/backtest.ts | 1 + frontend/src/views/backtest/New.vue | 8 ++++++++ sanguo_api/main.py | 13 +++++++++++++ 3 files changed, 22 insertions(+) diff --git a/frontend/src/api/backtest.ts b/frontend/src/api/backtest.ts index 1a7d899..e4ef2e5 100644 --- a/frontend/src/api/backtest.ts +++ b/frontend/src/api/backtest.ts @@ -6,6 +6,7 @@ export interface CtaSubmit { params: Record start: string end: string + benchmark?: string } export interface TaskStatus { diff --git a/frontend/src/views/backtest/New.vue b/frontend/src/views/backtest/New.vue index 55f83e0..bbe7720 100644 --- a/frontend/src/views/backtest/New.vue +++ b/frontend/src/views/backtest/New.vue @@ -16,6 +16,7 @@ const form = reactive({ symbol: '600000', start: '2024-01-01', end: '2024-06-30', + benchmark: 'hs300', }) const paramValues = reactive>({}) @@ -65,6 +66,7 @@ async function onSubmit(): Promise { params, start: form.start, end: form.end, + benchmark: form.benchmark, }) ElMessage.success('回测已提交') router.push(`/backtest/progress/${tid}`) @@ -103,6 +105,12 @@ async function onSubmit(): Promise { + + + + + + 提交回测 diff --git a/sanguo_api/main.py b/sanguo_api/main.py index 2a12440..ba81c35 100644 --- a/sanguo_api/main.py +++ b/sanguo_api/main.py @@ -72,6 +72,19 @@ def build_app(config_path: str = "config/backtest.yaml", static_dir: str | None app.mount("/", StaticFiles(directory=static_dir, html=True), name="spa") + # SPA history fallback: deep links like /backtest/result/:id hit StaticFiles + # (no such file) → 404. For browser navigation (Accept: text/html) serve + # index.html so vue-router can take over; API 404s (Accept: application/json) + # still return JSON. This makes refresh/bookmark of any SPA route work. + from starlette.exceptions import HTTPException as StarletteHTTPException + from starlette.responses import JSONResponse + + @app.exception_handler(StarletteHTTPException) + async def _spa_fallback(request, exc): # noqa: ANN001 + if exc.status_code == 404 and "text/html" in request.headers.get("accept", ""): + return FileResponse(index_html) + return JSONResponse({"detail": exc.detail}, status_code=exc.status_code) + return app