blob: b29a85673ae557cd87956ac702d9680d53d69479 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
<script lang="ts">
import Page from '../components/Page.svelte';
import Status from '../components/Status.svelte';
import { projectsStore } from '../lib/listsStore.svelte';
import { createProject } from '../lib/client';
import { extractStatusMessage } from '../lib/state';
import { go } from '../lib/router';
import { fmtDateTime } from '../lib/format';
let busy = $state(false);
let error = $state<string | null>(null);
let creating = $state(false);
let showCreate = $state(false);
let newName = $state('');
let newDesc = $state('');
let createErr = $state<string | null>(null);
async function load() {
busy = true;
error = null;
try {
await projectsStore.load();
} catch (e) {
error = extractStatusMessage(e);
} finally {
busy = false;
}
}
async function create(e: SubmitEvent) {
e.preventDefault();
if (!newName.trim()) return;
creating = true;
createErr = null;
try {
const p = await createProject(newName.trim(), newDesc.trim() || undefined);
projectsStore.bump(p);
showCreate = false;
newName = '';
newDesc = '';
go(`/projects/${p.id}/data`);
} catch (err) {
createErr = extractStatusMessage(err);
} finally {
creating = false;
}
}
</script>
<Page title="我的项目" subtitle="每个项目持有独立的策略代码版本、数据集与回测记录">
{#snippet actions()}
<button class="btn primary" onclick={() => (showCreate = !showCreate)} aria-expanded={showCreate}>
{showCreate ? '取消新建' : '新建项目'}
</button>
{/snippet}
<div class="stack">
<Status {busy} {error} busyText="加载项目列表…" empty={null} />
{#if showCreate}
<form class="card stack" onsubmit={create}>
<h2>新建项目</h2>
<div>
<label for="pn">项目名称</label>
<input id="pn" bind:value={newName} required placeholder="例如:双均线ETF轮动" />
</div>
<div>
<label for="pd">简介(可选)</label>
<input id="pd" bind:value={newDesc} placeholder="一句话说明研究思路" />
</div>
{#if createErr}<div class="banner error" role="alert">{createErr}</div>{/if}
<div class="row">
<button type="submit" class="btn primary" disabled={creating || !newName.trim()}>
{creating ? '创建中…' : '创建项目'}
</button>
</div>
</form>
{/if}
{#if !busy && !error && projectsStore.all.length === 0}
<Status busy={false} empty="还没有项目" emptyHint="点击右上角「新建项目」开始你的第一个策略研究" />
{/if}
{#if projectsStore.all.length > 0}
<div class="card" style="padding:0.4rem 0.6rem;">
<table class="data">
<thead>
<tr>
<th>名称</th>
<th>简介</th>
<th>版本代</th>
<th>最近更新</th>
</tr>
</thead>
<tbody>
{#each projectsStore.all as p (p.id)}
<tr>
<td><a href={`#/projects/${p.id}/data`} class="p-name">{p.name}</a></td>
<td class="hint">{p.description ?? '—'}</td>
<td class="num">{p.draft_generation ?? '—'}</td>
<td>{fmtDateTime(p.updated_at)}</td>
</tr>
{/each}
</tbody>
</table>
</div>
{/if}
</div>
</Page>
<style>
.p-name { font-weight: 600; }
</style>
|