summaryrefslogtreecommitdiff
path: root/frontend/src/pages/ProjectBacktestTab.svelte
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-18 12:03:32 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-18 12:03:32 +0800
commit61f5c545953bb4ee20b123bf9671ac35d7f1f3c1 (patch)
tree9ede3483db5f7e0d81189f2d29514892b8f77867 /frontend/src/pages/ProjectBacktestTab.svelte
parent1f16a357213611a6d7f84e506064fc0d9c6317c6 (diff)
downloadstrategy-lab-61f5c545953bb4ee20b123bf9671ac35d7f1f3c1.tar.gz
[变更性质] feat(frontend)
[新增功能] round3 页面组件全量迁移 shadcn-svelte(12 页面 + Modal/DatasetWizard/DatasetCard/Status) [实现方案] .btn→Button、.banner→Alert、table.data→Table.Root、.badge→Badge、.tabs→Tabs.Root、.metric-card/form.card→Card.Root;ProjectStrategyTab div 配对修复 [影响范围] src/pages/*.svelte、src/components/*.svelte
Diffstat (limited to 'frontend/src/pages/ProjectBacktestTab.svelte')
-rw-r--r--frontend/src/pages/ProjectBacktestTab.svelte113
1 files changed, 58 insertions, 55 deletions
diff --git a/frontend/src/pages/ProjectBacktestTab.svelte b/frontend/src/pages/ProjectBacktestTab.svelte
index baa9e5f..a9e7799 100644
--- a/frontend/src/pages/ProjectBacktestTab.svelte
+++ b/frontend/src/pages/ProjectBacktestTab.svelte
@@ -12,6 +12,11 @@
} from '../lib/format';
import { summarizeCoverage } from '../lib/coverage';
import type { Run, Dataset } from '../lib/types';
+ import { Button } from '$lib/components/ui/button';
+ import { Alert } from '$lib/components/ui/alert';
+ import { Badge } from '$lib/components/ui/badge';
+ import * as Card from '$lib/components/ui/card';
+ import * as Table from '$lib/components/ui/table';
interface Props {
projectId: string;
@@ -219,7 +224,7 @@
</script>
<div class="stack">
- <section class="card stack">
+ <Card.Root size="sm" class="stack-sec">
<h2>发起回测</h2>
<Status busy={busyDatasets} error={cfgErr} busyText="检查就绪的数据集…" empty={null} />
{#if !busyDatasets && datasetsReady.length === 0 && !cfgErr}
@@ -262,7 +267,7 @@
</label>
</div>
{#if needAck}
- <div class="banner warn" role="alert">
+ <Alert variant="default" class="bg-[var(--warn-soft)] border-[#f0ddb4]">
<span aria-hidden="true">⚠</span>
<div>
该数据集存在覆盖/预警信息,需要明确知晓后才能启动:
@@ -274,25 +279,25 @@
我已知晓并用当前数据继续
</label>
</div>
- </div>
+ </Alert>
{/if}
<div class="row">
- <button class="btn primary" onclick={startRun} disabled={!datasetId}>开始回测</button>
+ <Button onclick={startRun} disabled={!datasetId}>开始回测</Button>
{#if selectedDataset}
<span class="hint">本次回测与该数据集、当前策略快照一同记录,可按原始条件重跑</span>
{/if}
</div>
<Status busy={false} error={cfgErr} empty={actionMsg} />
{/if}
- </section>
+ </Card.Root>
- <section class="card stack">
+ <Card.Root size="sm" class="stack-sec">
<div class="spread">
<h2>最近一次回测</h2>
{#if latest}
<span class="row">
- <span class="badge">Run 分支 {latest.version_id?.slice(0,8) ?? "—"}</span>
- <span class="badge {runStatusBadge[latest.status]}">{runStatusLabel[latest.status]}</span>
+ <Badge variant="outline">Run 分支 {latest.version_id?.slice(0,8) ?? '—'}</Badge>
+ <Badge variant={runStatusBadge[latest.status] === 'ok' ? 'secondary' : runStatusBadge[latest.status] === 'warn' ? 'outline' : 'destructive'}>{runStatusLabel[latest.status]}</Badge>
</span>
{/if}
</div>
@@ -305,80 +310,78 @@
error={latestErr}
/>
<div class="rows-grid">
- <table class="data kv">
- <tbody>
- <tr><th>启动时间</th><td>{fmtDateTime(latest.created_at)}</td></tr>
- {#if latest.started_at}<tr><th>开始执行</th><td>{fmtDateTime(latest.started_at)}</td></tr>{/if}
- {#if latest.finished_at}<tr><th>结束时间</th><td>{fmtDateTime(latest.finished_at)}</td></tr>{/if}
- <tr><th>代码版本</th><td><span class="num">{latest.version_id.slice(0, 10)}</span></td></tr>
- <tr><th>数据集</th><td><span class="num">{latest.dataset_id?.slice(0, 8)}…</span></td></tr>
- <tr><th>资金</th><td>{formatMoney(latest.config.capital)} · 佣金 {fmtPct(latest.config.commission, 4)} · 滑点 {fmtPct(latest.config.slippage, 4)}</td></tr>
- </tbody>
- </table>
+ <Table.Root>
+ <Table.Body>
+ <Table.Row><Table.Head>启动时间</Table.Head><Table.Cell>{fmtDateTime(latest.created_at)}</Table.Cell></Table.Row>
+ {#if latest.started_at}<Table.Row><Table.Head>开始执行</Table.Head><Table.Cell>{fmtDateTime(latest.started_at)}</Table.Cell></Table.Row>{/if}
+ {#if latest.finished_at}<Table.Row><Table.Head>结束时间</Table.Head><Table.Cell>{fmtDateTime(latest.finished_at)}</Table.Cell></Table.Row>{/if}
+ <Table.Row><Table.Head>代码版本</Table.Head><Table.Cell><span class="num">{latest.version_id.slice(0, 10)}</span></Table.Cell></Table.Row>
+ <Table.Row><Table.Head>数据集</Table.Head><Table.Cell><span class="num">{latest.dataset_id?.slice(0, 8)}…</span></Table.Cell></Table.Row>
+ <Table.Row><Table.Head>资金</Table.Head><Table.Cell>{formatMoney(latest.config.capital)} · 佣金 {fmtPct(latest.config.commission, 4)} · 滑点 {fmtPct(latest.config.slippage, 4)}</Table.Cell></Table.Row>
+ </Table.Body>
+ </Table.Root>
</div>
{#if latest.error}
- <div class="banner error" role="alert"><span aria-hidden="true">✕</span><span>{latest.error}</span></div>
+ <Alert variant="destructive" class="bg-[var(--danger-soft)] border-[#f2c7c7]"><span aria-hidden="true">✕</span><span>{latest.error}</span></Alert>
{/if}
{#if latest.result?.warnings?.length}
- <div class="banner warn" role="alert">
+ <Alert variant="default" class="bg-[var(--warn-soft)] border-[#f0ddb4]">
<span aria-hidden="true">⚠</span>
<ul class="plain-list">
{#each latest.result.warnings as w, i (i)}<li>{w}</li>{/each}
</ul>
- </div>
+ </Alert>
{/if}
{#if latest.status === 'succeeded' && latest.result}
- <a class="btn" href={`#/projects/${projectId}/results?run=${latest.id}`}>查看完整结果与图表</a>
+ <Button variant="outline" href={`#/projects/${projectId}/results?run=${latest.id}`}>查看完整结果与图表</Button>
{/if}
<div class="row">
{#if canCancel}
- <button class="btn danger" onclick={onCancel} disabled={cancelBusy}>
+ <Button variant="destructive" onclick={onCancel} disabled={cancelBusy}>
{cancelBusy ? '取消中…' : '取消回测'}
- </button>
+ </Button>
{/if}
{#if canRerun}
- <button class="btn" onclick={onRerun} disabled={rerunBusy}>
+ <Button variant="outline" onclick={onRerun} disabled={rerunBusy}>
{rerunBusy ? '重新提交…' : '按原始代码&数据重跑'}
- </button>
+ </Button>
{/if}
</div>
{:else}
<Status busy={false} empty="项目还没有回测记录" emptyHint="在上方选择数据集并启动一次回测" />
{/if}
- </section>
+ </Card.Root>
- <section class="stack">
+ <div class="stack">
<h2>回测历史</h2>
<Status busy={historyBusy} error={historyErr} busyText="载入历史…" empty={null} />
{#if history && history.length > 0}
- <div class="card" style="padding:0.4rem 0.6rem">
- <table class="data">
- <thead>
- <tr>
- <th>启动时间</th>
- <th>状态</th>
- <th>资金/佣金/滑点</th>
- <th>数据集</th>
- <th>结果</th>
- </tr>
- </thead>
- <tbody>
+ <div class="px-3 py-2 rounded-[var(--radius-lg)] border border-border bg-card">
+ <Table.Root>
+ <Table.Header>
+ <Table.Row>
+ <Table.Head>启动时间</Table.Head>
+ <Table.Head>状态</Table.Head>
+ <Table.Head>资金/佣金/滑点</Table.Head>
+ <Table.Head>数据集</Table.Head>
+ <Table.Head>结果</Table.Head>
+ </Table.Row>
+ </Table.Header>
+ <Table.Body>
{#each history as h (h.id)}
- <tr>
- <td>{fmtDateTime(h.created_at)}</td>
- <td>{h.status === 'succeeded' ? '完成' : h.status === 'failed' ? '失败' : h.status === 'running' ? '执行中' : h.status === 'cancelled' ? '已取消' : '排队中'}</td>
- <td>
- {formatMoney(h.config.capital)} · {fmtPct(h.config.commission, 4)} / {fmtPct(h.config.slippage, 4)}
- </td>
- <td class="num">{h.dataset_id?.slice(0, 8)}…</td>
- <td>
- <a class="btn small" href={`#/projects/${projectId}/results?run=${h.id}`}>结果</a>
- </td>
- </tr>
+ <Table.Row>
+ <Table.Cell>{fmtDateTime(h.created_at)}</Table.Cell>
+ <Table.Cell>{h.status === 'succeeded' ? '完成' : h.status === 'failed' ? '失败' : h.status === 'running' ? '执行中' : h.status === 'cancelled' ? '已取消' : '排队中'}</Table.Cell>
+ <Table.Cell>{formatMoney(h.config.capital)} · {fmtPct(h.config.commission, 4)} / {fmtPct(h.config.slippage, 4)}</Table.Cell>
+ <Table.Cell class="num">{h.dataset_id?.slice(0, 8)}…</Table.Cell>
+ <Table.Cell>
+ <Button variant="outline" size="sm" href={`#/projects/${projectId}/results?run=${h.id}`}>结果</Button>
+ </Table.Cell>
+ </Table.Row>
{/each}
- </tbody>
- </table>
+ </Table.Body>
+ </Table.Root>
</div>
{/if}
- </section>
-</div>
+ </div>
+ </div>