lumencode 0.4.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -38
- package/index.js +79 -10
- package/lib/aggregate.js +40 -6
- package/lib/cache.js +8 -0
- package/lib/git.js +24 -2
- package/lib/report.js +14 -14
- package/lib/server.js +523 -412
- package/package.json +1 -1
- package/public/api.js +6 -0
- package/public/app.js +699 -526
- package/public/charts.js +285 -95
- package/public/config.js +22 -21
- package/public/git-insights.js +39 -113
- package/public/index.html +728 -341
- package/public/style.css +829 -1702
- package/public/ui-state.js +8 -67
- package/public/utils.js +10 -0
- package/public/work-report.js +1 -22
package/public/index.html
CHANGED
|
@@ -1,341 +1,728 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>LumenCode</title>
|
|
7
|
-
<link rel="
|
|
8
|
-
<
|
|
9
|
-
<link rel="stylesheet" href="/
|
|
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
|
-
<div
|
|
106
|
-
<div
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
</div>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
<
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
<
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
<
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
</
|
|
341
|
-
</
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>LumenCode</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter+Tight:wght@200;300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;600&display=swap">
|
|
10
|
+
<link rel="stylesheet" href="/style.css">
|
|
11
|
+
<script defer src="/vendor/chart.umd.min.js"></script>
|
|
12
|
+
</head>
|
|
13
|
+
<body>
|
|
14
|
+
<div id="app" class="app-grid" :class="railCollapsed ? 'rail-collapsed' : ''" x-data="app()" x-init="init()" x-cloak>
|
|
15
|
+
<!-- ── Rail ── -->
|
|
16
|
+
<aside class="rail" :class="railCollapsed ? 'collapsed' : ''">
|
|
17
|
+
<template x-if="!railCollapsed">
|
|
18
|
+
<div style="display:flex;flex-direction:column;flex:1;">
|
|
19
|
+
<div class="rail-header">
|
|
20
|
+
<div style="display:flex;align-items:center;gap:8px;width:100%;">
|
|
21
|
+
<div class="rail-title"><span class="text-aurora-shimmer" x-text="appName.slice(0, 5)"></span><span x-text="appName.slice(5)"></span></div>
|
|
22
|
+
<a class="rail-gh-link" href="https://github.com/yaowen51888-rich/lumencode" target="_blank" rel="noopener" title="GitHub">
|
|
23
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
|
24
|
+
</a>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="rail-subtitle">AI coding observability</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<nav class="rail-nav">
|
|
30
|
+
<span class="rail-nav-label">DATA SOURCES</span>
|
|
31
|
+
<ul class="rail-nav-list">
|
|
32
|
+
<li>
|
|
33
|
+
<button class="rail-nav-item" :class="activeTool === 'all' ? 'active' : ''" @click="setTool('all')" :style="activeTool === 'all' ? 'border-left-color: ' + colors.rust : ''">
|
|
34
|
+
<span class="source-mark-stacked"><span style="background: var(--claude)"></span><span style="background: var(--codex)"></span><span style="background: var(--opencode)"></span></span>
|
|
35
|
+
<div class="rail-nav-meta">
|
|
36
|
+
<div class="rail-nav-meta-top"><span class="rail-nav-name">全部工具</span><span class="rail-nav-tokens" x-text="toolTokens.all"></span></div>
|
|
37
|
+
<div class="rail-nav-meta-bottom"><span class="rail-nav-sub">ALL SOURCES</span><span class="rail-nav-sessions" x-text="toolSessions.all + ' sess'"></span></div>
|
|
38
|
+
</div>
|
|
39
|
+
</button>
|
|
40
|
+
</li>
|
|
41
|
+
<template x-for="tool in availableTools" :key="tool.name">
|
|
42
|
+
<li>
|
|
43
|
+
<button class="rail-nav-item" :class="activeTool === tool.name ? 'active' : ''" @click="setTool(tool.name)" :style="activeTool === tool.name ? 'border-left-color: ' + (toolColors[tool.name] || colors.rust) : ''">
|
|
44
|
+
<span class="source-mark" :style="'background: ' + (toolColors[tool.name] || colors.rust)"></span>
|
|
45
|
+
<div class="rail-nav-meta">
|
|
46
|
+
<div class="rail-nav-meta-top"><span class="rail-nav-name" x-text="tool.displayName"></span><span class="rail-nav-tokens" x-text="toolTokens[tool.name] || '-'"></span></div>
|
|
47
|
+
<div class="rail-nav-meta-bottom"><span class="rail-nav-sub" x-text="toolSubNames[tool.name] || tool.name.toUpperCase()"></span><span class="rail-nav-sessions" x-text="(toolSessions[tool.name] || 0) + ' sess'"></span></div>
|
|
48
|
+
</div>
|
|
49
|
+
</button>
|
|
50
|
+
</li>
|
|
51
|
+
</template>
|
|
52
|
+
</ul>
|
|
53
|
+
</nav>
|
|
54
|
+
|
|
55
|
+
<div class="rail-footer">
|
|
56
|
+
<div style="display:flex;align-items:center;justify-content:space-between;width:100%;">
|
|
57
|
+
<div style="display:flex;align-items:center;gap:8px;">
|
|
58
|
+
<span class="rail-dot"></span>
|
|
59
|
+
<span class="font-mono" style="font-size:10px;letter-spacing:0.12em;opacity:0.4" x-text="appName.toUpperCase() + ' / ' + appVersion"></span>
|
|
60
|
+
</div>
|
|
61
|
+
<div style="display:flex;align-items:center;gap:4px;">
|
|
62
|
+
<button class="rail-btn-icon" @click="toggleTheme()" :title="theme === 'dark' ? '切换日间模式' : '切换夜间模式'">
|
|
63
|
+
<svg x-show="theme !== 'dark'" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
|
64
|
+
<svg x-show="theme === 'dark'" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72 1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
|
65
|
+
</button>
|
|
66
|
+
<button class="rail-btn-icon" @click="railCollapsed = true" title="折叠">
|
|
67
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 17l-5-5 5-5M18 17l-5-5 5-5"/></svg>
|
|
68
|
+
</button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</template>
|
|
74
|
+
|
|
75
|
+
<template x-if="railCollapsed">
|
|
76
|
+
<div style="display:flex;flex-direction:column;align-items:center;padding-top:16px;gap:8px;">
|
|
77
|
+
<button class="rail-btn-icon" @click="railCollapsed = false" title="展开">
|
|
78
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 17l5-5-5-5M6 17l5-5-5-5"/></svg>
|
|
79
|
+
</button>
|
|
80
|
+
<button class="rail-btn-icon" @click="toggleTheme()" :title="theme === 'dark' ? '切换日间模式' : '切换夜间模式'">
|
|
81
|
+
<svg x-show="theme !== 'dark'" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
|
82
|
+
<svg x-show="theme === 'dark'" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72 1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
|
83
|
+
</button>
|
|
84
|
+
<div style="margin: 12px 0;"><span class="rail-dot"></span></div>
|
|
85
|
+
<div style="display:flex;flex-direction:column;align-items:center;gap:4px;">
|
|
86
|
+
<button class="rail-nav-item" :class="activeTool === 'all' ? 'active' : ''" @click="setTool('all')" title="全部工具">
|
|
87
|
+
<span class="source-mark-stacked" style="width:10px;height:10px"><span style="background:var(--claude);flex:1"></span><span style="background:var(--codex);flex:1"></span><span style="background:var(--opencode);flex:1"></span></span>
|
|
88
|
+
</button>
|
|
89
|
+
<template x-for="tool in availableTools" :key="tool.name">
|
|
90
|
+
<button class="rail-nav-item" :class="activeTool === tool.name ? 'active' : ''" @click="setTool(tool.name)" :title="tool.displayName">
|
|
91
|
+
<span class="source-mark" :style="'background:' + (toolColors[tool.name] || colors.rust)"></span>
|
|
92
|
+
</button>
|
|
93
|
+
</template>
|
|
94
|
+
</div>
|
|
95
|
+
<div style="margin-top:auto;padding-bottom:16px;">
|
|
96
|
+
<span class="rail-status-dot" style="width:6px;height:6px"></span>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</template>
|
|
100
|
+
</aside>
|
|
101
|
+
|
|
102
|
+
<!-- ── Main ── -->
|
|
103
|
+
<main class="main-content">
|
|
104
|
+
<!-- ===== LEDGER VIEW ===== -->
|
|
105
|
+
<div x-show="view === 'ledger'" style="display:block;">
|
|
106
|
+
<div style="padding: 32px 48px;">
|
|
107
|
+
<!-- Header -->
|
|
108
|
+
<div style="display:flex;align-items:flex-end;justify-content:space-between;gap:24px;margin-bottom:16px;">
|
|
109
|
+
<div>
|
|
110
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
|
|
111
|
+
<span class="label" x-text="periodMeta.en + ' · ' + periodMeta.cn"></span>
|
|
112
|
+
<span style="width:4px;height:4px;border-radius:50%;background:var(--foreground);opacity:0.3"></span>
|
|
113
|
+
<span class="label" x-text="activeTool === 'all' ? 'ALL SOURCES' : (toolSubNames[activeTool] || activeTool.toUpperCase())"></span>
|
|
114
|
+
</div>
|
|
115
|
+
<h1 style="font-size:40px;line-height:1.05;font-weight:500;letter-spacing:-0.02em;">
|
|
116
|
+
使用<span x-text="periodMeta.cn"></span>报<span style="opacity:0.4;font-weight:200"> · <span x-text="periodMeta.en === 'DAY' ? 'Daily' : periodMeta.en === 'WEEK' ? 'Weekly' : 'Monthly'"></span> Report</span>
|
|
117
|
+
</h1>
|
|
118
|
+
</div>
|
|
119
|
+
<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
|
|
120
|
+
<button class="btn btn-outline" @click="openSettings()">
|
|
121
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
|
122
|
+
设置
|
|
123
|
+
</button>
|
|
124
|
+
<button class="btn btn-outline" @click="exportCSV()"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> CSV</button>
|
|
125
|
+
<button class="btn btn-outline" @click="exportJSON()"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg> JSON</button>
|
|
126
|
+
<button class="btn btn-outline" @click="exportHTML()"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> HTML</button>
|
|
127
|
+
<button class="btn btn-primary" @click="openReport()">
|
|
128
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
|
|
129
|
+
工作汇报 <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
<!-- Period Switcher -->
|
|
135
|
+
<div style="margin-bottom:8px;">
|
|
136
|
+
<div class="period-switcher">
|
|
137
|
+
<template x-for="p in periods" :key="p.id">
|
|
138
|
+
<button class="period-btn" :class="period === p.id ? 'active' : ''" @click="setPeriod(p.id)">
|
|
139
|
+
<span x-text="p.cn"></span>
|
|
140
|
+
<span class="en" x-text="p.en"></span>
|
|
141
|
+
</button>
|
|
142
|
+
</template>
|
|
143
|
+
<div class="period-nav" x-show="period !== 'custom'">
|
|
144
|
+
<button @click="shiftDate(-1)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg></button>
|
|
145
|
+
<span class="period-date" x-text="dateDisplay"></span>
|
|
146
|
+
<button @click="shiftDate(1)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg></button>
|
|
147
|
+
<input type="date" id="dateInput" x-model="currentDate" @change="onDateChange" :max="today" style="position:absolute;opacity:0;width:1px;height:1px;">
|
|
148
|
+
<button @click="document.getElementById('dateInput').showPicker()"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg></button>
|
|
149
|
+
</div>
|
|
150
|
+
<div class="custom-range-picker" x-show="period === 'custom'" x-cloak>
|
|
151
|
+
<input type="date" x-model="customStart" @change="onCustomStartChange()" :max="today" class="custom-date-input" placeholder="开始日期">
|
|
152
|
+
<span style="opacity:0.4;font-size:12px;">—</span>
|
|
153
|
+
<input type="date" x-model="customEnd" @change="onCustomEndChange()" :max="today" class="custom-date-input" placeholder="结束日期">
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<!-- KPI Strip -->
|
|
159
|
+
<div class="kpi-strip" id="kpiStrip">
|
|
160
|
+
<template x-for="(k, i) in kpiData" :key="k.label">
|
|
161
|
+
<div class="kpi-cell" :style="i < kpiData.length - 1 ? 'border-right:1px solid var(--border)' : ''">
|
|
162
|
+
<span class="label" x-text="k.sub"></span>
|
|
163
|
+
<div style="display:flex;align-items:baseline;gap:6px;margin-top:10px;">
|
|
164
|
+
<span class="kpi-value" x-text="k.value" :class="k.accent ? 'text-aurora-shimmer' : ''"></span>
|
|
165
|
+
<span class="font-mono kpi-unit" x-text="k.unit" x-show="k.unit"></span>
|
|
166
|
+
</div>
|
|
167
|
+
<div class="kpi-bottom">
|
|
168
|
+
<span style="font-size:11px;opacity:0.65" x-text="k.label"></span>
|
|
169
|
+
<span class="delta" :class="k.trend" x-show="k.delta">
|
|
170
|
+
<svg x-show="k.trend === 'up'" width="11" height="11" viewBox="0 0 24 24" fill="none" :stroke="'var(--forest)'" stroke-width="2"><polyline points="7 17 17 7"/><polyline points="7 7 17 7 17 17"/></svg>
|
|
171
|
+
<svg x-show="k.trend === 'down'" width="11" height="11" viewBox="0 0 24 24" fill="none" :stroke="'var(--dest)'" stroke-width="2"><polyline points="7 7 17 17"/><polyline points="17 7 17 17 7 17"/></svg>
|
|
172
|
+
<svg x-show="k.trend === 'flat'" width="11" height="11" viewBox="0 0 24 24" fill="none" :stroke="'var(--clay)'" stroke-width="2"><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
|
173
|
+
<span x-text="k.delta"></span>
|
|
174
|
+
</span>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</template>
|
|
178
|
+
</div>
|
|
179
|
+
|
|
180
|
+
<!-- No data hint -->
|
|
181
|
+
<div class="no-data-hint" x-show="!hasData && !loading && !error" style="display:none;">该时间段暂无使用数据</div>
|
|
182
|
+
|
|
183
|
+
<!-- §01 AI Contribution -->
|
|
184
|
+
<div x-show="hasData" style="margin-top:56px;">
|
|
185
|
+
<div class="section-head">
|
|
186
|
+
<span class="label section-head-num">01</span>
|
|
187
|
+
<h2 class="section-head-title">AI 贡献率</h2>
|
|
188
|
+
<span class="label section-head-en">/ AI CONTRIBUTION</span>
|
|
189
|
+
<span class="section-head-line"></span>
|
|
190
|
+
<span class="section-head-meta font-mono" style="font-size:10px;opacity:0.55" x-text="aiContributionMeta"></span>
|
|
191
|
+
</div>
|
|
192
|
+
|
|
193
|
+
<div class="ai-hero-grid">
|
|
194
|
+
<div class="ai-hero-cell">
|
|
195
|
+
<div style="display:flex;align-items:baseline;gap:24px;">
|
|
196
|
+
<div style="flex-shrink:0;">
|
|
197
|
+
<div class="ai-hero-pct"><span class="text-aurora-shimmer" x-text="aiLinePctDisplay"></span><span :style="'color:' + colors.rust">%</span></div>
|
|
198
|
+
<div class="ai-hero-desc" x-html="aiSummaryDesc"></div>
|
|
199
|
+
</div>
|
|
200
|
+
<div style="flex:1;padding-bottom:12px;">
|
|
201
|
+
<div style="display:flex;justify-content:space-between;margin-bottom:6px;">
|
|
202
|
+
<span class="label">ATTRIBUTION · 归因构成</span>
|
|
203
|
+
<span class="font-mono" style="font-size:10px;opacity:0.55" x-text="attributionPct"></span>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="attribution-bar" id="attributionBar">
|
|
206
|
+
<div class="bg-aurora-shimmer animate-bar-fill" :style="'width:' + confirmedPct + '%'"></div>
|
|
207
|
+
<div class="animate-bar-fill" :style="'width:' + inferredPct + '%;background:' + colors.ochre + ';animation-delay:0.15s'"></div>
|
|
208
|
+
<div class="animate-bar-fill" :style="'width:' + unattribPct + '%;background:var(--ink-18);animation-delay:0.3s'"></div>
|
|
209
|
+
</div>
|
|
210
|
+
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:8px;">
|
|
211
|
+
<div style="display:flex;align-items:baseline;gap:6px;">
|
|
212
|
+
<span style="width:6px;height:6px;margin-top:6px;flex-shrink:0;background:var(--forest)"></span>
|
|
213
|
+
<div style="flex:1;min-width:0;">
|
|
214
|
+
<span class="font-mono" style="font-size:9px;letter-spacing:0.18em;opacity:0.55;display:block">CONFIRMED</span>
|
|
215
|
+
<div style="display:flex;align-items:baseline;gap:6px;"><span style="font-size:14px">确认</span><span class="font-mono" style="font-size:12px;opacity:0.7" x-text="confirmedPct + '%'"></span></div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
<div style="display:flex;align-items:baseline;gap:6px;">
|
|
219
|
+
<span style="width:6px;height:6px;margin-top:6px;flex-shrink:0;background:var(--ochre)"></span>
|
|
220
|
+
<div style="flex:1;min-width:0;">
|
|
221
|
+
<span class="font-mono" style="font-size:9px;letter-spacing:0.18em;opacity:0.55;display:block">INFERRED</span>
|
|
222
|
+
<div style="display:flex;align-items:baseline;gap:6px;"><span style="font-size:14px">推断</span><span class="font-mono" style="font-size:12px;opacity:0.7" x-text="inferredPct + '%'"></span></div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
<div style="display:flex;align-items:baseline;gap:6px;">
|
|
226
|
+
<span style="width:6px;height:6px;margin-top:6px;flex-shrink:0;background:var(--ink-50)"></span>
|
|
227
|
+
<div style="flex:1;min-width:0;">
|
|
228
|
+
<span class="font-mono" style="font-size:9px;letter-spacing:0.18em;opacity:0.55;display:block">UNATTRIB.</span>
|
|
229
|
+
<div style="display:flex;align-items:baseline;gap:6px;"><span style="font-size:14px">未归因</span><span class="font-mono" style="font-size:12px;opacity:0.7" x-text="unattribPct + '%'"></span></div>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
<div class="ai-hero-cell">
|
|
237
|
+
<div style="display:flex;align-items:baseline;justify-content:space-between;margin-bottom:12px;">
|
|
238
|
+
<span class="label">BY SOURCE · 各工具占比</span>
|
|
239
|
+
<span class="font-mono" style="font-size:10px;opacity:0.55">≈ stacked</span>
|
|
240
|
+
</div>
|
|
241
|
+
<div class="source-bar" id="sourceBar">
|
|
242
|
+
<div :style="'width:' + sourceClaudePct + '%;background:var(--claude)'"></div>
|
|
243
|
+
<div :style="'width:' + sourceCodexPct + '%;background:var(--codex)'"></div>
|
|
244
|
+
<div :style="'width:' + sourceOpencodePct + '%;background:var(--opencode)'"></div>
|
|
245
|
+
</div>
|
|
246
|
+
<div style="margin-top:16px;display:flex;flex-direction:column;gap:10px;" id="sourceLegend">
|
|
247
|
+
<template x-for="s in sourceBreakdown" :key="s.name">
|
|
248
|
+
<div style="display:grid;grid-template-columns:14px 1fr 64px 72px;align-items:baseline;gap:12px;">
|
|
249
|
+
<span style="width:10px;height:10px;" :style="'background:' + s.color"></span>
|
|
250
|
+
<span style="font-size:13px" x-text="s.name"></span>
|
|
251
|
+
<span class="font-mono" style="font-size:12px;text-align:right" x-text="s.pct + '%'"></span>
|
|
252
|
+
<span class="font-mono" style="font-size:11px;text-align:right;opacity:0.55" x-text="s.tokens"></span>
|
|
253
|
+
</div>
|
|
254
|
+
</template>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<!-- Git Output + Attribution Detail Strip -->
|
|
260
|
+
<div class="data-strip">
|
|
261
|
+
<div class="data-strip-row" style="grid-template-columns: 140px repeat(4, 1fr);">
|
|
262
|
+
<div class="data-strip-label"><span class="label">GIT 产出</span></div>
|
|
263
|
+
<template x-for="(k, i) in gitOutputCells" :key="k.en">
|
|
264
|
+
<div class="data-strip-cell" :style="i < 3 ? 'border-right:1px solid var(--border)' : ''">
|
|
265
|
+
<div style="display:flex;flex-direction:column;">
|
|
266
|
+
<span class="data-strip-en" x-text="k.en"></span>
|
|
267
|
+
<span class="data-strip-cn" x-text="k.l"></span>
|
|
268
|
+
</div>
|
|
269
|
+
<span class="data-strip-value" :style="k.c ? 'color:' + k.c : ''" x-text="k.v"></span>
|
|
270
|
+
</div>
|
|
271
|
+
</template>
|
|
272
|
+
</div>
|
|
273
|
+
<div class="data-strip-row" style="grid-template-columns: 140px repeat(6, 1fr);">
|
|
274
|
+
<div class="data-strip-label"><span class="label">归因明细</span></div>
|
|
275
|
+
<template x-for="(k, i) in attributionCells" :key="k.en">
|
|
276
|
+
<div class="data-strip-cell" :style="i < 5 ? 'border-right:1px solid var(--border)' : ''">
|
|
277
|
+
<div style="display:flex;flex-direction:column;min-width:0;">
|
|
278
|
+
<span class="data-strip-en truncate" x-text="k.en"></span>
|
|
279
|
+
<span class="data-strip-cn truncate" x-text="k.l"></span>
|
|
280
|
+
</div>
|
|
281
|
+
<span class="data-strip-value" style="font-size:16px;flex-shrink:0;white-space:nowrap" :style="k.c ? 'color:' + k.c : ''" x-text="k.v"></span>
|
|
282
|
+
</div>
|
|
283
|
+
</template>
|
|
284
|
+
</div>
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
<!-- §02 + §03 -->
|
|
289
|
+
<div x-show="hasData" class="grid-5-7">
|
|
290
|
+
<!-- §02 Edit Types -->
|
|
291
|
+
<div>
|
|
292
|
+
<div class="section-head">
|
|
293
|
+
<span class="label section-head-num">02</span>
|
|
294
|
+
<h2 class="section-head-title">提交类型分析</h2>
|
|
295
|
+
<span class="label section-head-en">/ EDIT TYPES</span>
|
|
296
|
+
<span class="section-head-line"></span>
|
|
297
|
+
</div>
|
|
298
|
+
<div class="card" style="padding:24px;">
|
|
299
|
+
<div id="editTypesContainer">
|
|
300
|
+
<template x-for="(e, i) in editTypeData" :key="e.name">
|
|
301
|
+
<div class="bar-item">
|
|
302
|
+
<div class="bar-top">
|
|
303
|
+
<span style="font-size:13px;display:flex;align-items:baseline;gap:10px;">
|
|
304
|
+
<span class="font-mono" style="font-size:10px;opacity:0.4" x-text="String(i+1).padStart(2,'0')"></span>
|
|
305
|
+
<span x-text="e.name"></span>
|
|
306
|
+
</span>
|
|
307
|
+
<span class="font-mono" style="font-size:11px" x-text="e.value"></span>
|
|
308
|
+
</div>
|
|
309
|
+
<div class="bar-track"><div class="bar-fill" :style="'width:' + e.pct + '%;background:' + e.color"></div></div>
|
|
310
|
+
</div>
|
|
311
|
+
</template>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
|
|
316
|
+
<!-- §03 Top Files -->
|
|
317
|
+
<div>
|
|
318
|
+
<div class="section-head">
|
|
319
|
+
<span class="label section-head-num">03</span>
|
|
320
|
+
<h2 class="section-head-title">改动文件 Top 10</h2>
|
|
321
|
+
<span class="label section-head-en">/ TOP FILES</span>
|
|
322
|
+
<span class="section-head-line"></span>
|
|
323
|
+
<span class="section-head-meta font-mono" style="font-size:10px;opacity:0.55" x-text="topFilesMeta"></span>
|
|
324
|
+
</div>
|
|
325
|
+
<div class="card" id="topFilesContainer">
|
|
326
|
+
<div class="top-files-header">
|
|
327
|
+
<span class="label">#</span>
|
|
328
|
+
<span class="label">PATH</span>
|
|
329
|
+
<span class="label text-right">COMMITS</span>
|
|
330
|
+
<span class="label text-right" style="color:var(--forest)">+ ADDED</span>
|
|
331
|
+
<span class="label text-right" style="color:var(--dest)">− REMOVED</span>
|
|
332
|
+
</div>
|
|
333
|
+
<template x-for="(f, i) in topFilesData" :key="f.path">
|
|
334
|
+
<div class="top-files-row row-lift" :class="i < topFilesData.length - 1 ? 'with-border' : ''">
|
|
335
|
+
<span class="font-mono" style="font-size:10px;opacity:0.4" x-text="String(i+1).padStart(2,'0')"></span>
|
|
336
|
+
<span class="font-mono truncate" style="font-size:12px" x-text="f.path" :title="f.path"></span>
|
|
337
|
+
<span class="font-mono text-right" style="font-size:12px" x-text="f.commits"></span>
|
|
338
|
+
<span class="font-mono text-right" style="font-size:12px;color:var(--forest)" x-text="'+' + f.plus"></span>
|
|
339
|
+
<span class="font-mono text-right" style="font-size:12px;color:var(--dest)" x-text="'−' + f.minus"></span>
|
|
340
|
+
</div>
|
|
341
|
+
</template>
|
|
342
|
+
</div>
|
|
343
|
+
</div>
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
<!-- §04 + §05 + §06 -->
|
|
347
|
+
<div x-show="hasData" class="grid-3-cols">
|
|
348
|
+
<!-- §04 Work Type -->
|
|
349
|
+
<div>
|
|
350
|
+
<div class="section-head">
|
|
351
|
+
<span class="label section-head-num">04</span>
|
|
352
|
+
<h2 class="section-head-title">工作类型</h2>
|
|
353
|
+
<span class="label section-head-en">/ WORK TYPE</span>
|
|
354
|
+
<span class="section-head-line"></span>
|
|
355
|
+
</div>
|
|
356
|
+
<div class="card" style="padding:24px;">
|
|
357
|
+
<div style="position:relative;height:200px;">
|
|
358
|
+
<canvas id="workTypeChart"></canvas>
|
|
359
|
+
<div class="pie-center">
|
|
360
|
+
<div style="font-size:28px;font-weight:200;line-height:1;">100%</div>
|
|
361
|
+
<span class="label" style="margin-top:4px" x-text="workTypeData.filter(w=>!w.hidden).length + ' CATEGORIES'"></span>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
<div style="margin-top:16px;padding-top:12px;border-top:1px solid var(--border);display:grid;grid-template-columns:1fr 1fr;gap:6px 16px;" id="workTypeLegend">
|
|
365
|
+
<template x-for="(w, i) in workTypeData" :key="w.name">
|
|
366
|
+
<div @click="toggleWorkType(i)" :style="{display:'flex',alignItems:'center',gap:'6px',cursor:'pointer',userSelect:'none',opacity:w.hidden?0.3:1}">
|
|
367
|
+
<span :style="{width:'10px',height:'10px',borderRadius:'2px',flexShrink:'0',background:w.color}"></span>
|
|
368
|
+
<span style="font-size:12px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" x-text="w.name"></span>
|
|
369
|
+
<span class="font-mono text-right" style="font-size:11px;opacity:0.6;flex-shrink:0;" x-text="w.value + '%'"></span>
|
|
370
|
+
</div>
|
|
371
|
+
</template>
|
|
372
|
+
</div>
|
|
373
|
+
</div>
|
|
374
|
+
</div>
|
|
375
|
+
|
|
376
|
+
<!-- §05 Model Mix -->
|
|
377
|
+
<div>
|
|
378
|
+
<div class="section-head">
|
|
379
|
+
<span class="label section-head-num">05</span>
|
|
380
|
+
<h2 class="section-head-title">模型分布</h2>
|
|
381
|
+
<span class="label section-head-en">/ MODEL MIX</span>
|
|
382
|
+
<span class="section-head-line"></span>
|
|
383
|
+
</div>
|
|
384
|
+
<div class="card" style="padding:24px;">
|
|
385
|
+
<div id="modelBarsContainer" style="display:flex;flex-direction:column;gap:14px;">
|
|
386
|
+
<template x-for="(m, i) in modelData" :key="m.name">
|
|
387
|
+
<div>
|
|
388
|
+
<div style="display:flex;justify-content:space-between;align-items:baseline;margin-bottom:4px;">
|
|
389
|
+
<span class="font-mono truncate" style="font-size:11px;max-width:70%" x-text="m.name"></span>
|
|
390
|
+
<span class="font-mono" style="font-size:11px;opacity:0.55" x-text="m.pct + '%'"></span>
|
|
391
|
+
</div>
|
|
392
|
+
<div class="bar-track"><div class="bar-fill" :style="'width:' + m.barPct + '%;background:' + (i === 0 ? colors.rust : 'var(--foreground)')"></div></div>
|
|
393
|
+
</div>
|
|
394
|
+
</template>
|
|
395
|
+
</div>
|
|
396
|
+
<div style="margin-top:20px;padding-top:16px;border-top:1px solid var(--border);display:grid;grid-template-columns:1fr 1fr;gap:12px;">
|
|
397
|
+
<div><span class="label">TOP MODEL</span><div style="font-size:14px;margin-top:4px" x-text="topModelName"></div></div>
|
|
398
|
+
<div><span class="label">ACTIVE</span><div style="font-size:14px;margin-top:4px" x-text="activeModels"></div></div>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
|
|
403
|
+
<!-- §06 Cache -->
|
|
404
|
+
<div>
|
|
405
|
+
<div class="section-head">
|
|
406
|
+
<span class="label section-head-num">06</span>
|
|
407
|
+
<h2 class="section-head-title">缓存命中率</h2>
|
|
408
|
+
<span class="label section-head-en">/ CACHE EFFICACY</span>
|
|
409
|
+
<span class="section-head-line"></span>
|
|
410
|
+
</div>
|
|
411
|
+
<div class="card" style="padding:24px;">
|
|
412
|
+
<div style="display:flex;align-items:baseline;justify-content:space-between;margin-bottom:12px;">
|
|
413
|
+
<div style="font-size:40px;font-weight:200;line-height:1;color:var(--forest)">
|
|
414
|
+
<span x-text="cacheHitRate"></span><span style="font-size:20px">%</span>
|
|
415
|
+
</div>
|
|
416
|
+
<span class="delta up" x-show="cacheDelta">
|
|
417
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="var(--forest)" stroke-width="2"><polyline points="7 17 17 7"/><polyline points="7 7 17 7 17 17"/></svg>
|
|
418
|
+
<span x-text="cacheDelta"></span>
|
|
419
|
+
</span>
|
|
420
|
+
</div>
|
|
421
|
+
<div style="display:flex;height:8px;margin-bottom:16px;">
|
|
422
|
+
<template x-for="(c, i) in cacheData" :key="c.label">
|
|
423
|
+
<div :style="'width:' + c.value + '%;background:' + c.color + (i < cacheData.length - 1 ? ';border-right:2px solid var(--card)' : '')"></div>
|
|
424
|
+
</template>
|
|
425
|
+
</div>
|
|
426
|
+
<div style="display:flex;flex-direction:column;gap:8px;">
|
|
427
|
+
<template x-for="c in cacheData" :key="c.label">
|
|
428
|
+
<div style="display:grid;grid-template-columns:12px 1fr 40px 44px;align-items:baseline;gap:8px;">
|
|
429
|
+
<span style="width:8px;height:8px;" :style="'background:' + c.color"></span>
|
|
430
|
+
<span style="font-size:13px" x-text="c.label"></span>
|
|
431
|
+
<span class="font-mono" style="font-size:10px;opacity:0.45" x-text="c.en"></span>
|
|
432
|
+
<span class="font-mono text-right" style="font-size:12px" x-text="c.value + '%'"></span>
|
|
433
|
+
</div>
|
|
434
|
+
</template>
|
|
435
|
+
</div>
|
|
436
|
+
<div x-show="cacheSavingText" style="margin-top:20px;padding-top:16px;border-top:1px solid var(--border);font-size:12px;opacity:0.65;line-height:1.6;" x-html="cacheSavingText"></div>
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
|
|
441
|
+
<!-- §07 Time Series -->
|
|
442
|
+
<div x-show="hasData" style="margin-top:56px;">
|
|
443
|
+
<div class="section-head">
|
|
444
|
+
<span class="label section-head-num">07</span>
|
|
445
|
+
<h2 class="section-head-title">时间活动</h2>
|
|
446
|
+
<span class="label section-head-en">/ TIME SERIES</span>
|
|
447
|
+
<span class="section-head-line"></span>
|
|
448
|
+
<div class="section-head-meta" style="display:flex;align-items:center;gap:16px;">
|
|
449
|
+
<span class="font-mono" style="font-size:10px;opacity:0.55;display:inline-flex;align-items:center;gap:6px;">
|
|
450
|
+
<span style="width:12px;height:1px;background:var(--foreground)"></span> SESSIONS
|
|
451
|
+
</span>
|
|
452
|
+
<span class="font-mono" style="font-size:10px;opacity:0.55;display:inline-flex;align-items:center;gap:6px;">
|
|
453
|
+
<span style="width:12px;height:4px;background:var(--rust);opacity:0.35"></span> TOKENS (M)
|
|
454
|
+
</span>
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
<div class="card" style="padding:24px;">
|
|
458
|
+
<div class="chart-wrap-tall"><canvas id="timelineChart"></canvas></div>
|
|
459
|
+
<div style="margin-top:16px;display:grid;grid-template-columns:repeat(4,1fr);gap:24px;padding-top:16px;border-top:1px solid var(--border);">
|
|
460
|
+
<template x-for="x in timelineMeta" :key="x.l">
|
|
461
|
+
<div>
|
|
462
|
+
<span class="label" x-text="x.l"></span>
|
|
463
|
+
<div style="font-size:20px;font-weight:200;margin-top:4px;" x-text="x.v"></div>
|
|
464
|
+
<div style="font-size:11px;opacity:0.45;margin-top:2px;" x-text="x.s"></div>
|
|
465
|
+
</div>
|
|
466
|
+
</template>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
</div>
|
|
470
|
+
|
|
471
|
+
<!-- §08 + §09 -->
|
|
472
|
+
<div x-show="hasData" class="grid-2-cols">
|
|
473
|
+
<!-- §08 Projects -->
|
|
474
|
+
<div>
|
|
475
|
+
<div class="section-head">
|
|
476
|
+
<span class="label section-head-num">08</span>
|
|
477
|
+
<h2 class="section-head-title">项目分布</h2>
|
|
478
|
+
<span class="label section-head-en">/ PROJECTS</span>
|
|
479
|
+
<span class="section-head-line"></span>
|
|
480
|
+
</div>
|
|
481
|
+
<div class="card" style="padding:24px;">
|
|
482
|
+
<div class="chart-wrap"><canvas id="projectChart"></canvas></div>
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
|
|
486
|
+
<!-- §09 Tool Calls -->
|
|
487
|
+
<div>
|
|
488
|
+
<div class="section-head">
|
|
489
|
+
<span class="label section-head-num">09</span>
|
|
490
|
+
<h2 class="section-head-title">工具调用排行</h2>
|
|
491
|
+
<span class="label section-head-en">/ TOOL CALLS</span>
|
|
492
|
+
<span class="section-head-line"></span>
|
|
493
|
+
</div>
|
|
494
|
+
<div class="card" style="padding:24px;">
|
|
495
|
+
<div id="toolCallsContainer" style="display:flex;flex-direction:column;gap:12px;">
|
|
496
|
+
<template x-for="(t, i) in toolRankData" :key="t.name">
|
|
497
|
+
<div class="tool-rank">
|
|
498
|
+
<span class="font-mono" style="font-size:10px;opacity:0.4" x-text="String(i+1).padStart(2,'0')"></span>
|
|
499
|
+
<span class="font-mono" style="font-size:12px" x-text="t.name"></span>
|
|
500
|
+
<div class="bar-track"><div class="bar-fill" :style="'width:' + t.pct + '%;background:' + (i === 0 ? colors.rust : 'var(--foreground)')"></div></div>
|
|
501
|
+
<span class="font-mono text-right" style="font-size:11px" x-text="t.value"></span>
|
|
502
|
+
</div>
|
|
503
|
+
</template>
|
|
504
|
+
</div>
|
|
505
|
+
</div>
|
|
506
|
+
</div>
|
|
507
|
+
</div>
|
|
508
|
+
|
|
509
|
+
<!-- Footer -->
|
|
510
|
+
<div style="margin-top:48px;padding-top:24px;border-top:1px solid var(--border);display:flex;justify-content:space-between;">
|
|
511
|
+
<span class="font-mono" style="font-size:10px;text-transform:uppercase;letter-spacing:0.18em;opacity:0.55" x-text="appName.toLowerCase() + ' · ' + appVersion"></span>
|
|
512
|
+
<span class="font-mono" style="font-size:10px;text-transform:uppercase;letter-spacing:0.18em;opacity:0.55" x-text="'generated ' + generatedAt"></span>
|
|
513
|
+
</div>
|
|
514
|
+
</div>
|
|
515
|
+
</div>
|
|
516
|
+
|
|
517
|
+
<!-- ===== REPORT VIEW ===== -->
|
|
518
|
+
<div x-show="view === 'report'" style="display:none;">
|
|
519
|
+
<div style="padding: 32px 48px;">
|
|
520
|
+
<!-- Toolbar -->
|
|
521
|
+
<div class="report-toolbar">
|
|
522
|
+
<button class="btn btn-outline" @click="view = 'ledger'" style="display:inline-flex;align-items:center;gap:6px;font-size:13px;">
|
|
523
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
|
|
524
|
+
返回数据分析
|
|
525
|
+
</button>
|
|
526
|
+
<span style="flex:1;height:1px;background:var(--border)"></span>
|
|
527
|
+
<div style="display:flex;border:1px solid var(--border);border-radius:6px;overflow:hidden;">
|
|
528
|
+
<button class="period-btn" :class="reportLevel === 'detailed' ? 'active' : ''" @click="setReportLevel('detailed')" style="border-left:none">详细 Detail</button>
|
|
529
|
+
<button class="period-btn" :class="reportLevel === 'brief' ? 'active' : ''" @click="setReportLevel('brief')">简略 Brief</button>
|
|
530
|
+
</div>
|
|
531
|
+
<button class="btn btn-outline" @click="copyReport()" style="display:inline-flex;align-items:center;gap:6px;">
|
|
532
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
|
533
|
+
<span x-text="copied ? '已复制' : '复制'"></span>
|
|
534
|
+
</button>
|
|
535
|
+
<button class="btn btn-outline" @click="downloadReport()" style="display:inline-flex;align-items:center;gap:6px;">
|
|
536
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
|
|
537
|
+
.md
|
|
538
|
+
</button>
|
|
539
|
+
<div style="display:flex;border:1px solid var(--border);border-radius:6px;overflow:hidden;">
|
|
540
|
+
<button class="period-btn" :class="reportPlatform === 'default' ? 'active' : ''" @click="setReportPlatform('default')" style="border-left:none">默认</button>
|
|
541
|
+
<button class="period-btn" :class="reportPlatform === 'feishu' ? 'active' : ''" @click="setReportPlatform('feishu')">飞书</button>
|
|
542
|
+
<button class="period-btn" :class="reportPlatform === 'dingtalk' ? 'active' : ''" @click="setReportPlatform('dingtalk')">钉钉</button>
|
|
543
|
+
</div>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<!-- Report Header -->
|
|
547
|
+
<div class="report-header">
|
|
548
|
+
<div style="display:flex;align-items:flex-end;justify-content:space-between;gap:24px;margin-bottom:16px;">
|
|
549
|
+
<div>
|
|
550
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;">
|
|
551
|
+
<span class="label">WORK REPORT · 工作汇报</span>
|
|
552
|
+
<span style="width:4px;height:4px;border-radius:50%;background:var(--foreground);opacity:0.3"></span>
|
|
553
|
+
<span class="label" x-text="periodMeta.en"></span>
|
|
554
|
+
<span style="width:4px;height:4px;border-radius:50%;background:var(--foreground);opacity:0.3"></span>
|
|
555
|
+
<span class="label" x-text="reportLevel === 'detailed' ? 'DETAIL' : 'BRIEF'"></span>
|
|
556
|
+
</div>
|
|
557
|
+
<h1 style="font-size:36px;line-height:1.05;font-weight:500;letter-spacing:-0.02em;">
|
|
558
|
+
AI 编码助手 · 工作<span x-text="periodMeta.cn"></span>报
|
|
559
|
+
</h1>
|
|
560
|
+
<div style="margin-top:8px;font-size:13px;opacity:0.55" x-text="reportSubTitle"></div>
|
|
561
|
+
</div>
|
|
562
|
+
<span class="font-mono" style="font-size:10px;text-transform:uppercase;letter-spacing:0.18em;opacity:0.55">TRACE-ID <span x-text="traceId"></span></span>
|
|
563
|
+
</div>
|
|
564
|
+
<div class="period-switcher">
|
|
565
|
+
<template x-for="p in periods" :key="p.id">
|
|
566
|
+
<button class="period-btn" :class="period === p.id ? 'active' : ''" @click="setPeriod(p.id)">
|
|
567
|
+
<span x-text="p.cn"></span>
|
|
568
|
+
<span class="en" x-text="p.en"></span>
|
|
569
|
+
</button>
|
|
570
|
+
</template>
|
|
571
|
+
<div class="period-nav" x-show="period !== 'custom'">
|
|
572
|
+
<button @click="shiftDate(-1)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg></button>
|
|
573
|
+
<span class="period-date" x-text="dateDisplay"></span>
|
|
574
|
+
<button @click="shiftDate(1)"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg></button>
|
|
575
|
+
</div>
|
|
576
|
+
<div class="custom-range-picker" x-show="period === 'custom'" x-cloak>
|
|
577
|
+
<input type="date" x-model="customStart" @change="onCustomStartChange()" :max="today" class="custom-date-input">
|
|
578
|
+
<span style="opacity:0.4;font-size:12px;">—</span>
|
|
579
|
+
<input type="date" x-model="customEnd" @change="onCustomEndChange()" :max="today" class="custom-date-input">
|
|
580
|
+
</div>
|
|
581
|
+
</div>
|
|
582
|
+
</div>
|
|
583
|
+
|
|
584
|
+
<!-- Report KPIs -->
|
|
585
|
+
<div class="report-kpi-grid">
|
|
586
|
+
<template x-for="(x, i) in reportKpis" :key="x.l">
|
|
587
|
+
<div class="report-kpi-cell" :class="{ 'kpi-bottom-border': i < 2 }">
|
|
588
|
+
<span class="label" x-text="x.l"></span>
|
|
589
|
+
<div style="font-size:36px;font-weight:200;line-height:1;margin-top:12px;letter-spacing:-0.02em;" :class="x.accent ? 'text-aurora-shimmer' : ''" x-text="x.v"></div>
|
|
590
|
+
<div style="font-size:12px;opacity:0.55;margin-top:8px;" x-text="x.s"></div>
|
|
591
|
+
</div>
|
|
592
|
+
</template>
|
|
593
|
+
</div>
|
|
594
|
+
|
|
595
|
+
<!-- Report Content -->
|
|
596
|
+
<div style="margin-top:48px;display:grid;grid-template-columns:5fr 2fr;gap:24px;">
|
|
597
|
+
<div class="work-report-content" id="reportContent" x-html="reportHtml"></div>
|
|
598
|
+
|
|
599
|
+
<!-- Sticky Meta Panel -->
|
|
600
|
+
<aside>
|
|
601
|
+
<div style="position:sticky;top:32px;display:flex;flex-direction:column;gap:20px;">
|
|
602
|
+
<div class="card" style="padding:20px;">
|
|
603
|
+
<span class="label">SUMMARY · 摘要</span>
|
|
604
|
+
<p style="font-size:13px;line-height:1.7;opacity:0.85;margin-top:12px;" x-html="reportSummary"></p>
|
|
605
|
+
</div>
|
|
606
|
+
<!-- Project Selector -->
|
|
607
|
+
<div class="card" style="padding:16px 20px;" x-show="reportProjects.length > 1" x-cloak>
|
|
608
|
+
<span class="label">PROJECTS · 项目</span>
|
|
609
|
+
<div class="proj-list">
|
|
610
|
+
<button class="proj-item" :class="reportProject === '' ? 'active' : ''" @click="setReportProject('')">全部</button>
|
|
611
|
+
<template x-for="p in reportProjects" :key="p">
|
|
612
|
+
<button class="proj-item" :class="reportProject === p ? 'active' : ''" @click="setReportProject(p)" x-text="p"></button>
|
|
613
|
+
</template>
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
<div class="card">
|
|
617
|
+
<div style="padding:14px 20px;border-bottom:1px solid var(--border);"><span class="label">HIGHLIGHTS · 看点</span></div>
|
|
618
|
+
<div style="display:flex;flex-direction:column;">
|
|
619
|
+
<template x-for="h in reportHighlights" :key="h.l">
|
|
620
|
+
<div :style="{display:'flex',alignItems:'baseline',justifyContent:'space-between',gap:'12px',padding:'12px 20px',borderBottom:h.last?'none':'1px solid var(--border)'}">
|
|
621
|
+
<span style="font-size:13px;opacity:0.7;white-space:nowrap" x-text="h.l"></span>
|
|
622
|
+
<span class="font-mono" style="font-size:13px;text-align:right;" :style="h.c ? 'color:' + h.c : ''" x-text="h.v"></span>
|
|
623
|
+
</div>
|
|
624
|
+
</template>
|
|
625
|
+
</div>
|
|
626
|
+
</div>
|
|
627
|
+
<div style="font-size:11px;opacity:0.55;line-height:1.6;padding:0 4px;">
|
|
628
|
+
<span class="label">NOTE</span>
|
|
629
|
+
<p style="margin-top:8px;">本报告基于本地 sessions 与 git commit 日志生成,不上传任何代码与环境变量。</p>
|
|
630
|
+
</div>
|
|
631
|
+
</div>
|
|
632
|
+
</aside>
|
|
633
|
+
</div>
|
|
634
|
+
|
|
635
|
+
<!-- Report Footer -->
|
|
636
|
+
<div style="margin-top:48px;padding-top:24px;border-top:1px solid var(--border);display:flex;justify-content:space-between;">
|
|
637
|
+
<span class="font-mono" style="font-size:10px;text-transform:uppercase;letter-spacing:0.18em;opacity:0.55" x-text="reportLevel === 'detailed' ? 'DETAIL EDITION' : 'BRIEF EDITION'"></span>
|
|
638
|
+
<span class="font-mono" style="font-size:10px;text-transform:uppercase;letter-spacing:0.18em;opacity:0.55" x-text="'compiled ' + generatedAt"></span>
|
|
639
|
+
</div>
|
|
640
|
+
</div>
|
|
641
|
+
</div>
|
|
642
|
+
</main>
|
|
643
|
+
</div>
|
|
644
|
+
|
|
645
|
+
<!-- ── Settings Modal ── -->
|
|
646
|
+
<div id="settingsModal" class="modal-overlay" style="display:none;">
|
|
647
|
+
<div class="modal-backdrop" onclick="document.getElementById('settingsModal').style.display='none'"></div>
|
|
648
|
+
<div class="modal-panel">
|
|
649
|
+
<div class="modal-header">
|
|
650
|
+
<h3 style="font-size:15px;font-weight:500;">配置</h3>
|
|
651
|
+
<button class="rail-btn-icon" onclick="document.getElementById('settingsModal').style.display='none'" style="color:var(--foreground);opacity:0.65;">
|
|
652
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
653
|
+
</button>
|
|
654
|
+
</div>
|
|
655
|
+
<div class="modal-body">
|
|
656
|
+
<div class="form-group"><label class="form-label">Claude 日志目录</label><input type="text" id="cfgClaudeDir" class="form-input"></div>
|
|
657
|
+
<div class="form-group"><label class="form-label">本地项目路径(每行一个)</label><textarea id="cfgRepos" class="form-textarea" rows="3"></textarea></div>
|
|
658
|
+
<div class="form-group"><label class="form-label">排除项目(每行一个)</label><textarea id="cfgExclude" class="form-textarea" rows="3"></textarea></div>
|
|
659
|
+
<div class="form-group"><label class="form-label">场景关键词</label><textarea id="cfgKeywords" class="form-textarea" rows="5"></textarea><p class="form-hint">JSON 格式,如 { "coding": ["实现", "开发"] }</p></div>
|
|
660
|
+
</div>
|
|
661
|
+
<div class="modal-footer"><button class="btn btn-primary" onclick="saveSettings()">保存</button></div>
|
|
662
|
+
</div>
|
|
663
|
+
</div>
|
|
664
|
+
|
|
665
|
+
<!-- ── Drill Modal ── -->
|
|
666
|
+
<div id="drillModal" class="modal-overlay" style="display:none;">
|
|
667
|
+
<div class="modal-backdrop" onclick="document.getElementById('drillModal').style.display='none'"></div>
|
|
668
|
+
<div class="modal-panel">
|
|
669
|
+
<div class="modal-header">
|
|
670
|
+
<h3 style="font-size:15px;font-weight:500;" id="drillTitle">明细</h3>
|
|
671
|
+
<button class="rail-btn-icon" onclick="document.getElementById('drillModal').style.display='none'" style="color:var(--foreground);opacity:0.65;">
|
|
672
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
673
|
+
</button>
|
|
674
|
+
</div>
|
|
675
|
+
<div class="modal-body" id="drillBody"></div>
|
|
676
|
+
</div>
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
<!-- ── Toast ── -->
|
|
680
|
+
<div id="toast" class="toast" style="display:none;"></div>
|
|
681
|
+
|
|
682
|
+
<!-- ── Welcome Page ── -->
|
|
683
|
+
<div id="welcomePage" class="welcome-page" style="display:none;">
|
|
684
|
+
<div class="welcome-card card">
|
|
685
|
+
<div class="welcome-brand">
|
|
686
|
+
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" style="margin-bottom:16px;">
|
|
687
|
+
<rect x="8" y="12" width="32" height="24" rx="6" stroke="var(--foreground)" stroke-width="2.5" fill="none"/>
|
|
688
|
+
<path d="M16 22L22 28L32 18" stroke="var(--foreground)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
689
|
+
</svg>
|
|
690
|
+
<h1 class="welcome-title">欢迎使用 LumenCode</h1>
|
|
691
|
+
<p class="welcome-subtitle">AI 编码助手使用统计与代码产出分析工具</p>
|
|
692
|
+
</div>
|
|
693
|
+
<div style="display:flex;flex-direction:column;gap:16px;margin-bottom:32px;">
|
|
694
|
+
<div style="display:flex;align-items:center;gap:12px;padding:12px;border:1px solid var(--border);border-radius:8px;">
|
|
695
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
|
|
696
|
+
<div><h4 style="font-size:14px;font-weight:500;">Token 消耗追踪</h4><p style="font-size:12px;opacity:0.55;">按日/周/月统计输入、输出、缓存命中</p></div>
|
|
697
|
+
</div>
|
|
698
|
+
<div style="display:flex;align-items:center;gap:12px;padding:12px;border:1px solid var(--border);border-radius:8px;">
|
|
699
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="9"/><path d="M12 6v6l4 2"/></svg>
|
|
700
|
+
<div><h4 style="font-size:14px;font-weight:500;">费用估算</h4><p style="font-size:12px;opacity:0.55;">基于模型定价自动计算成本</p></div>
|
|
701
|
+
</div>
|
|
702
|
+
<div style="display:flex;align-items:center;gap:12px;padding:12px;border:1px solid var(--border);border-radius:8px;">
|
|
703
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
|
|
704
|
+
<div><h4 style="font-size:14px;font-weight:500;">AI 贡献度</h4><p style="font-size:12px;opacity:0.55;">关联 Git 提交,量化 AI 辅助占比</p></div>
|
|
705
|
+
</div>
|
|
706
|
+
</div>
|
|
707
|
+
<div style="display:flex;flex-direction:column;gap:16px;margin-bottom:24px;">
|
|
708
|
+
<div style="padding:16px;border:1px solid var(--border);border-radius:8px;">
|
|
709
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;"><span style="display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:var(--foreground);color:var(--background);font-size:11px;font-weight:600;">1</span><h3 style="font-size:14px;font-weight:500;">选择 Claude 日志目录</h3></div>
|
|
710
|
+
<p style="font-size:12px;opacity:0.55;margin-bottom:8px;">Claude Code 会话日志的存放路径,通常是 <code style="font-family:var(--font-mono);font-size:11px;background:var(--secondary);padding:2px 6px;border-radius:4px;">~/.claude</code></p>
|
|
711
|
+
<input type="text" id="welcomeClaudeDir" class="form-input" placeholder="例如: C:/Users/xxx/.claude">
|
|
712
|
+
</div>
|
|
713
|
+
<div style="padding:16px;border:1px solid var(--border);border-radius:8px;">
|
|
714
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px;"><span style="display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;border-radius:50%;background:var(--foreground);color:var(--background);font-size:11px;font-weight:600;">2</span><h3 style="font-size:14px;font-weight:500;">选择项目仓库(可选)</h3></div>
|
|
715
|
+
<p style="font-size:12px;opacity:0.55;margin-bottom:8px;">用于关联 Git 代码产出统计,多个仓库用逗号分隔</p>
|
|
716
|
+
<input type="text" id="welcomeRepos" class="form-input" placeholder="例如: D:/project1, D:/project2">
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
<div style="text-align:center;">
|
|
720
|
+
<button class="btn btn-primary" id="welcomeStartBtn" style="width:100%;">开始使用</button>
|
|
721
|
+
<p id="welcomeHint" style="margin-top:8px;font-size:12px;"></p>
|
|
722
|
+
</div>
|
|
723
|
+
</div>
|
|
724
|
+
</div>
|
|
725
|
+
|
|
726
|
+
<script type="module" src="/app.js"></script>
|
|
727
|
+
</body>
|
|
728
|
+
</html>
|