feat: integrate chatbox research with datasets and backtests

This commit is contained in:
yuxuanhui
2026-09-08 12:43:00 +08:00
parent 43336ad960
commit aef8e1d310
37 changed files with 1421 additions and 42 deletions
+35 -6
View File
@@ -28,6 +28,7 @@ import type {
Source,
} from "./types";
import "./style.css";
import { SourceDetails, sourceLabel } from "../research/SourceDetails";
export function BacktestPage({
active,
@@ -47,6 +48,8 @@ export function BacktestPage({
onContext: (context: PageContext) => void;
}) {
const [view, setView] = useState("runs");
const [sourceFilter, setSourceFilter] = useState("");
const [sourceKinds, setSourceKinds] = useState<string[]>([]);
const [page, setPage] = useState(1);
const [runs, setRuns] = useState<Page<Run>>({
items: [],
@@ -97,15 +100,19 @@ export function BacktestPage({
const [itemDetail, setItemDetail] = useState<Item | null>(null);
const refresh = useCallback(async () => {
const [r, d, c] = await Promise.all([
api<Page<Run>>(`/backtests/runs?offset=${(page - 1) * 25}`),
const [r, d, c, kinds] = await Promise.all([
api<Page<Run>>(
`/backtests/runs?offset=${(page - 1) * 25}&source=${encodeURIComponent(sourceFilter)}`,
),
api<Page<DraftSummary>>(`/backtests/drafts?offset=${(page - 1) * 25}`),
api<Scheduler>("/backtests/config"),
api<string[]>("/backtests/sources"),
]);
setRuns(r);
setDrafts(d);
setConfig(c);
}, [page]);
setSourceKinds(kinds);
}, [page, sourceFilter]);
useEffect(() => {
if (!active) return;
let alive = true;
@@ -293,6 +300,22 @@ export function BacktestPage({
]}
/>
<span className="muted">REGULAR · FASTEXPR</span>
{view === "runs" && (
<Select
aria-label="回测研究来源筛选"
value={sourceFilter || undefined}
placeholder="全部研究来源"
showClear
optionList={sourceKinds.map((kind) => ({
value: kind,
label: sourceLabel(kind),
}))}
onChange={(value) => {
setSourceFilter(String(value ?? ""));
setPage(1);
}}
/>
)}
<div className="backtest-spacer" />
<Button
type="tertiary"
@@ -337,7 +360,11 @@ export function BacktestPage({
</Button>
),
},
{ title: "来源", width: 120, render: (_, r) => r!.source.kind },
{
title: "来源",
width: 120,
render: (_, r) => sourceLabel(r!.source.kind),
},
{
title: "状态",
width: 160,
@@ -438,8 +465,9 @@ export function BacktestPage({
</div>
<p>
{preview.name} · {preview.total} 条候选 · {preview.batch_count}{" "}
个平台批次 · 来源 {preview.source.kind}
个平台批次 · 来源 {sourceLabel(preview.source.kind)}
</p>
<SourceDetails source={preview.source} onAction={onAction} />
{preview.duplicate_count > 0 && (
<Banner
type="warning"
@@ -763,10 +791,11 @@ export function BacktestPage({
/>
)}
<p className="muted">
来源 {run.source.kind}{" "}
来源 {sourceLabel(run.source.kind)}{" "}
{run.source.batch_id ? `· 批次 ${run.source.batch_id}` : ""} ·{" "}
{formatTime(run.created_at, timezone)}
</p>
<SourceDetails source={run.source} onAction={onAction} />
{run.scheduler.blocked_reason && (
<Banner
type="warning"