summaryrefslogtreecommitdiff
path: root/frontend/src/pages/ProjectStrategyTab.svelte
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-18 08:26:57 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-18 08:26:57 +0800
commit45ecb4e9dfe225bc982e9af9315590bcb0783df7 (patch)
treee046f42ace89c09d60aa4f07db8450507364fdb5 /frontend/src/pages/ProjectStrategyTab.svelte
parent33cac3eef7d9962d8803cd812553549d6f555516 (diff)
downloadstrategy-lab-45ecb4e9dfe225bc982e9af9315590bcb0783df7.tar.gz
feat(frontend): 结果/实验/策略/数据页迁移 shadcn 与新 Chart API
[变更性质] 四个业务标签页与数据集卡片迁移 shadcn 组件,图表消费切换到 layerchart 长格式 API,功能与数据语义不变。 [新增功能] 结果页权益曲线(策略权益/现金/基准,基准可缺省)与回撤曲线(desc 面积)改由 Chart.svelte data/series 渲染;实验记录页多回测归一对比 曲线改为快速长格式行构造。空数据行允许 undefined 列(基准缺口), Chart data 类型放宽 [key:string]: string|number|undefined。 [实现方案] RunsPage:查看入口改 shadcn Button(href 语义保留 hash 路由), 对比图数据由 compareOption(echarts option)化为 compare。 ProjectResultsTab:图表开关、日志折叠用 Button;equityData/ drawdownData $derived 计算峰值回撤。ProjectStrategyTab:快照输入、 冲突/AI/版本操作迁移 Button/Input。ProjectDataTab 与 DatasetCard: shadcn 组件 + 保留 banner error/warn/info、retry-row 等 legacy class, "使用相同请求重新获取"重试入口与 onRecreated 逻辑不变,配套 datasetCardRetry/datasetCardWarnings/projectDataTabRecreated 回归 测试。resultsAccounting.test.ts:layerchart 在 jsdom 挂载约 3 秒, suite 全量下易撞默认 5s 超时,首测提高至 20s。 [影响范围] npm run check 0 error、58 tests 全绿、npm run build 通过;真浏览器 375/768/1440 图表页零溢出(artifacts/ui-shadcn 截图与探针 JSON)。
Diffstat (limited to 'frontend/src/pages/ProjectStrategyTab.svelte')
-rw-r--r--frontend/src/pages/ProjectStrategyTab.svelte35
1 files changed, 18 insertions, 17 deletions
diff --git a/frontend/src/pages/ProjectStrategyTab.svelte b/frontend/src/pages/ProjectStrategyTab.svelte
index 5f2e242..0df9f1a 100644
--- a/frontend/src/pages/ProjectStrategyTab.svelte
+++ b/frontend/src/pages/ProjectStrategyTab.svelte
@@ -3,6 +3,8 @@
import CodeEditor from '../components/CodeEditor.svelte';
import DiffView from '../components/DiffView.svelte';
import Modal from '../components/Modal.svelte';
+ import { Button } from '$lib/components/ui/button';
+ import { Input } from '$lib/components/ui/input';
import { projectsStore } from '../lib/listsStore.svelte';
import {
getProject,
@@ -274,7 +276,7 @@
</p>
<CodeEditor value={code} onInput={onEditorInput} readOnly={false} label="策略源码" height={430} />
<div class="spread wrap">
- <input
+ <Input
bind:value={snapshotMessage}
placeholder="快照说明,例如:加入RSI过滤器(可选)"
style="flex:2 1 240px"
@@ -282,16 +284,16 @@
if (ev.key === 'Enter') void snapshot();
}}
/>
- <button class="btn" disabled={snapshotBusy} onclick={snapshot}>
+ <Button disabled={snapshotBusy} onclick={snapshot}>
{snapshotBusy ? '创建快照…' : '保存版本快照'}
- </button>
- <button
- class="btn"
+ </Button>
+ <Button
+ variant="outline"
onclick={() => versions[1] && void compareWithDraft(versions[1])}
disabled={!versions[1]}
>
草稿与上一快照对比
- </button>
+ </Button>
</div>
<Status busy={false} error={snapshotErr} empty={snapshotMsg} />
@@ -304,8 +306,8 @@
</div>
<DiffView before={conflictServer.code} after={code} beforeLabel="服务器" afterLabel="本机" />
<div class="row">
- <button class="btn primary" onclick={keepMine}>保留本机修改(覆盖服务器)</button>
- <button class="btn" onclick={loadServer}>采用服务器版本</button>
+ <Button onclick={keepMine}>保留本机修改(覆盖服务器)</Button>
+ <Button variant="outline" onclick={loadServer}>采用服务器版本</Button>
</div>
{/if}
</div>
@@ -316,9 +318,9 @@
<label for="ai-instruction">希望 AI 帮你做什么?<span class="hint">例如:把均线周期改为两个可调参数并解释影响</span></label>
<textarea id="ai-instruction" rows="3" bind:value={instruction} placeholder="描述对策略的修改意图,AI 返回完整新源码与差异预览"></textarea>
<div class="row">
- <button class="btn primary" disabled={aiBusy || !instruction.trim()} onclick={askAI}>
+ <Button disabled={aiBusy || !instruction.trim()} onclick={askAI}>
{aiBusy ? 'AI 处理中…' : '获取建议'}
- </button>
+ </Button>
</div>
{#if aiErr}
<div class="banner error" role="alert">
@@ -341,15 +343,14 @@
<h3>与当前草稿的差异</h3>
<DiffView before={code} after={aiResult.proposed_code} beforeLabel="当前草稿" afterLabel="AI 建议" />
<div class="row">
- <button
- class="btn primary"
+ <Button
disabled={aiAcceptBusy}
onclick={acceptAI}
title={aiResult.base_generation !== baseGeneration ? '草稿代已变化,建议如需采用请重新获取' : ''}
>
{aiAcceptBusy ? '接受中…' : '接受为新版本'}
- </button>
- <button class="btn ghost" disabled={aiAcceptBusy} onclick={discardAI}>放弃建议</button>
+ </Button>
+ <Button variant="ghost" disabled={aiAcceptBusy} onclick={discardAI}>放弃建议</Button>
{#if aiResult.base_generation !== baseGeneration}
<span class="banner warn" role="alert">草稿代 {aiResult.base_generation} 与当前 {baseGeneration} 不一致,接受会失败;请重新发起说明</span>
{/if}
@@ -395,11 +396,11 @@
<td><span class="badge grey">{versionSourceLabel[v.source]}</span></td>
<td>
<div class="row">
- <button class="btn small" onclick={() => void compareWithDraft(v)}>对比当前</button>
+ <Button variant="outline" size="sm" onclick={() => void compareWithDraft(v)}>对比当前</Button>
{#if i + 1 < versions.length}
- <button class="btn small" onclick={() => void compareTwoVersions(i)}>与相邻旧版对比</button>
+ <Button variant="outline" size="sm" onclick={() => void compareTwoVersions(i)}>与相邻旧版对比</Button>
{/if}
- <button class="btn small" onclick={() => void restore(v)}>恢复为新草稿</button>
+ <Button size="sm" onclick={() => void restore(v)}>恢复为新草稿</Button>
</div>
</td>
</tr>