From c52a727d11b87d70ec00a7e2569841e6e6abcd9c Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Fri, 18 Sep 2026 18:11:53 +0800 Subject: [变更性质] 用户旅程重排:项目首页指标摘要+项目卡、结果页首屏 capital 三卡+交易分页、数据/策略/回测 CTA 与三态统一,token 白名单清扫(docs/ui-user-journey-round6.md §1/§2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/pages/ProjectResultsTab.svelte | 82 +++++++++++++++++++---------- 1 file changed, 53 insertions(+), 29 deletions(-) (limited to 'frontend/src/pages/ProjectResultsTab.svelte') diff --git a/frontend/src/pages/ProjectResultsTab.svelte b/frontend/src/pages/ProjectResultsTab.svelte index 181d6a4..860fab2 100644 --- a/frontend/src/pages/ProjectResultsTab.svelte +++ b/frontend/src/pages/ProjectResultsTab.svelte @@ -21,7 +21,8 @@ import * as Table from '$lib/components/ui/table'; import * as Select from '$lib/components/ui/select'; import * as Tabs from '$lib/components/ui/tabs'; - import type { Run, BacktestResult } from '../lib/types'; + import { go } from '../lib/router'; +import type { Run, BacktestResult } from '../lib/types'; interface Props { projectId: string; @@ -116,33 +117,49 @@ // 投入口径 reporting(任务 A):投入/持仓估值/回报,口径注明不含闲置现金 const cap = $derived(result ? capitalReporting(result) : null); - const tile = 'gap-1 min-w-0'; + const tile = 'p-4 flex flex-col gap-1 min-w-0'; const tileLabel = 'text-xs text-muted-foreground'; const tileValue = 'text-2xl font-bold tabular-nums text-foreground leading-tight break-all'; - const metricValueProps = 'data-testid="metric-value"'; + + let tradePage = $state(0); + const TRADE_PER_PAGE = 20; + const tradePageCount = $derived(result ? Math.max(1, Math.ceil(result.trades.length / TRADE_PER_PAGE)) : 1); + const tradePageRows = $derived(result ? result.trades.slice(tradePage * TRADE_PER_PAGE, (tradePage + 1) * TRADE_PER_PAGE) : []); -
-
+
+

回测结果

{#if run} - - Run {run.id.slice(0, 8)}… + + Run {run.id.slice(0, 8)}… {runStatusLabel[run.status]} {/if}
- + {#if busy} + + {:else if error} + + {#snippet errorCta()} + + {/snippet} + + {/if} {#if !busy && !error && !run} - + + {#snippet emptyCta()} + + {/snippet} + {/if} {#if run && !busy && !error} {#if history.length > 1} -
- 查看其他回测: +
+ 查看其他回测: {/if} - + {#if result.metrics} {@const mrow = result.metrics} -
+
总收益率
{fmtPct(mrow.total_return)}
年化收益率
{fmtPct(mrow.annual_return)}
最大回撤
{fmtPct(mrow.max_drawdown)}
@@ -193,14 +210,14 @@
{/if} {#if cap} -
+
累计投入
{formatMoney(cap.invested)}
最终持仓估值
{formatMoney(cap.holdingValue)}
投入回报率
{cap.returnPct ?? '—'}
-

投入口径不含初始账户闲置现金:累计投入 = 首日现金 − 末日现金;持仓估值 = 末日持仓 × 最新收盘价。

+

投入口径不含初始账户闲置现金:累计投入 = 首日现金 − 末日现金;持仓估值 = 末日持仓 × 最新收盘价。

{/if} -

+

平仓回合数为已完成的开仓并全部平仓的完整回合(1 个回合 = 1 次平仓),不含撤单与未平仓的单笔成交;成交记录中的“金额”为真实成交额(数量 × 成交价),非持仓成本。结果非投资建议;未完全模拟流动性/涨跌停等限制。 引擎 {result.engine?.name} {result.engine?.version} {#if result.elapsed_ms} · 耗时 {(result.elapsed_ms / 1000).toFixed(1)}s{/if} @@ -208,7 +225,7 @@

- + (chartMode = v as 'equity' | 'drawdown')} class="w-fit"> 权益曲线({result.equity.length} 点) @@ -226,7 +243,7 @@

订单与持仓记录

-

成交记录 ({result.trades.length})

+

成交记录 ({result.trades.length})

{#if result.trades.length > 0}
@@ -242,8 +259,8 @@ - {#each result.trades.slice(0, 80) as t, i (i)} - + {#each tradePageRows as t, i (tradePage * TRADE_PER_PAGE + i)} + {t.date} {t.symbol} {t.side === "buy" ? "买入" : "卖出"} @@ -256,28 +273,35 @@
- {#if result.trades.length > 80} -

仅显示前 80 条,共 {result.trades.length} 条

+ {#if result.trades.length > TRADE_PER_PAGE} +
+ + 第 {tradePage + 1} / {tradePageCount} 页 · 共 {result.trades.length} 条 + + + + +
{/if} {:else} -

本区间未发生成交

+

本区间未发生成交

{/if}
-

策略日志

- {#if logsOpen} -
{result.logs.join("\n")}
+
{result.logs.join("\n")}
{/if}
-

+

数据与引擎 - 本轮使用的引擎版本、耗时与消耗内存均在上方备注。 + 本轮使用的引擎版本、耗时与消耗内存均在上方备注。

-

+

结果由对应策略代码、配置、数据清单(数据哈希 {result.data_manifest_hash?.slice(0, 12)})以及当时引擎共同决定。

-- cgit v1.2.3