diff options
Diffstat (limited to 'frontend/src/pages/ProjectBacktestTab.svelte')
| -rw-r--r-- | frontend/src/pages/ProjectBacktestTab.svelte | 113 |
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> |
