fix: 深链SPA fallback(刷新/收藏结果页不再404) + 新建回测加基准选择器(hs300/zz500)
This commit is contained in:
@@ -6,6 +6,7 @@ export interface CtaSubmit {
|
|||||||
params: Record<string, unknown>
|
params: Record<string, unknown>
|
||||||
start: string
|
start: string
|
||||||
end: string
|
end: string
|
||||||
|
benchmark?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskStatus {
|
export interface TaskStatus {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const form = reactive({
|
|||||||
symbol: '600000',
|
symbol: '600000',
|
||||||
start: '2024-01-01',
|
start: '2024-01-01',
|
||||||
end: '2024-06-30',
|
end: '2024-06-30',
|
||||||
|
benchmark: 'hs300',
|
||||||
})
|
})
|
||||||
const paramValues = reactive<Record<string, string>>({})
|
const paramValues = reactive<Record<string, string>>({})
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ async function onSubmit(): Promise<void> {
|
|||||||
params,
|
params,
|
||||||
start: form.start,
|
start: form.start,
|
||||||
end: form.end,
|
end: form.end,
|
||||||
|
benchmark: form.benchmark,
|
||||||
})
|
})
|
||||||
ElMessage.success('回测已提交')
|
ElMessage.success('回测已提交')
|
||||||
router.push(`/backtest/progress/${tid}`)
|
router.push(`/backtest/progress/${tid}`)
|
||||||
@@ -103,6 +105,12 @@ async function onSubmit(): Promise<void> {
|
|||||||
<el-form-item label="结束日期">
|
<el-form-item label="结束日期">
|
||||||
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
|
<el-date-picker v-model="form.end" type="date" value-format="YYYY-MM-DD" style="width: 220px" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="基准">
|
||||||
|
<el-select v-model="form.benchmark" style="width: 220px">
|
||||||
|
<el-option label="沪深300 (hs300)" value="hs300" />
|
||||||
|
<el-option label="中证500 (zz500)" value="zz500" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" :loading="submitting" @click="onSubmit">提交回测</el-button>
|
<el-button type="primary" :loading="submitting" @click="onSubmit">提交回测</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
@@ -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")
|
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
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user