lumencode 0.4.3 → 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/public/index.html CHANGED
@@ -1,347 +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="stylesheet" href="/fonts/inter.css">
8
- <script src="/vendor/chart.umd.min.js"></script>
9
- <link rel="stylesheet" href="/style.css">
10
- </head>
11
- <body>
12
- <div id="toast" class="toast" style="display:none;"></div>
13
- <nav class="top-nav">
14
- <div class="nav-inner">
15
- <div class="logo">LumenCode</div>
16
- <div class="nav-controls">
17
- <div class="nav-pill-group">
18
- <button class="category-tab active" data-period="daily">日报</button>
19
- <button class="category-tab" data-period="weekly">周报</button>
20
- <button class="category-tab" data-period="monthly">月报</button>
21
- </div>
22
- <div style="display:flex;align-items:center;gap:4px;">
23
- <button id="prevDate" class="icon-btn" title="上一个" aria-label="上一个日期">
24
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="15 18 9 12 15 6"></polyline></svg>
25
- </button>
26
- <label for="dateInput" class="sr-only">选择日期</label>
27
- <input type="date" id="dateInput" class="text-input">
28
- <button id="nextDate" class="icon-btn" title="下一个" aria-label="下一个日期">
29
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
30
- </button>
31
- </div>
32
- <button id="themeBtn" class="icon-btn" title="切换暗色模式">
33
- <svg id="moonIcon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
34
- <svg id="sunIcon" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display:none"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>
35
- </button>
36
- <button id="settingsBtn" class="icon-btn" title="设置">
37
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><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"></path></svg>
38
- </button>
39
- </div>
40
- </div>
41
- </nav>
42
-
43
- <div class="app-layout">
44
- <aside class="tool-sidebar" :class="{ collapsed: collapsed }" x-data="toolTabs()" x-init="init()" x-show="availableTools.length > 0">
45
- <div class="tool-sidebar-header">
46
- <span class="tool-sidebar-title" x-show="!collapsed">数据源</span>
47
- <button class="tool-sidebar-toggle" @click="toggleCollapse()" :title="collapsed ? '展开' : '收起'">
48
- <svg x-show="!collapsed" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="11 17 6 12 11 7"></polyline><polyline points="18 17 13 12 18 7"></polyline></svg>
49
- <svg x-show="collapsed" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="13 17 18 12 13 7"></polyline><polyline points="6 17 11 12 6 7"></polyline></svg>
50
- </button>
51
- </div>
52
- <nav class="tool-nav">
53
- <button class="tool-nav-item" :class="{ active: activeTool === 'all' }" @click="setTool('all')" title="汇总">
54
- <span class="tool-dot tool-dot-all"></span>
55
- <span class="tool-nav-label" x-show="!collapsed">汇总</span>
56
- </button>
57
- <template x-for="tool in availableTools" :key="tool.name">
58
- <button
59
- class="tool-nav-item"
60
- :class="{ active: activeTool === tool.name, disabled: !tool.detected && !tool.enabled }"
61
- :disabled="!tool.detected && !tool.enabled"
62
- @click="setTool(tool.name)"
63
- :title="tool.displayName"
64
- >
65
- <span class="tool-dot" :class="'tool-dot-' + tool.name"></span>
66
- <span class="tool-nav-text" x-show="!collapsed">
67
- <span class="tool-nav-label" x-text="tool.displayName"></span>
68
- <span class="tool-nav-version" x-show="tool.version" x-text="'v' + tool.version"></span>
69
- </span>
70
- </button>
71
- </template>
72
- </nav>
73
- <!-- 添加数据源功能暂未实现,先隐藏
74
- <div class="tool-sidebar-footer">
75
- <button class="tool-nav-add" @click="showAddTool = true" title="添加数据源">
76
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
77
- <span class="tool-nav-label" x-show="!collapsed">添加</span>
78
- </button>
79
- </div>
80
- -->
81
- </aside>
82
-
83
- <main class="container" x-data="app()">
84
- <section class="hero-band">
85
- <div class="hero-row">
86
- <div>
87
- <h1 class="display-lg" id="reportTitle">Claude Code 使用日报</h1>
88
- <p class="body-md muted" id="reportDate">加载中...</p>
89
- </div>
90
- <div class="hero-actions" style="display:flex;gap:8px;">
91
- <button id="exportCsvBtn" class="btn-outline">导出 CSV</button>
92
- <button id="exportJsonBtn" class="btn-outline">导出 JSON</button>
93
- <button id="exportHtmlBtn" class="btn-outline">保存 HTML</button>
94
- <button id="printBtn" class="btn-outline">打印/PDF</button>
95
- <button id="workReportBtn" class="btn-outline">工作汇报</button>
96
- </div>
97
- </div>
98
- </section>
99
-
100
- <section class="stats-grid" id="statsGrid">
101
- <div class="feature-card">
102
- <div class="card-label">独立会话</div>
103
- <div class="card-value-row"><div class="card-value" id="statSessions">-</div><div class="card-trend" id="trendSessions"></div></div>
104
- </div>
105
- <div class="feature-card">
106
- <div class="card-label">交互轮次</div>
107
- <div class="card-value-row"><div class="card-value" id="statRequests">-</div><div class="card-trend" id="trendRequests"></div></div>
108
- </div>
109
- <div class="feature-card">
110
- <div class="card-label">覆盖项目</div>
111
- <div class="card-value-row"><div class="card-value" id="statProjects">-</div><div class="card-trend" id="trendProjects"></div></div>
112
- </div>
113
- <div class="feature-card">
114
- <div class="card-label">Token 消耗</div>
115
- <div class="card-value-row"><div class="card-value" id="statTokens">-</div><div class="card-trend" id="trendTokens"></div></div>
116
- <div class="card-sub" id="statTokenBreakdown"></div>
117
- </div>
118
- <div class="feature-card">
119
- <div class="card-label">预估费用</div>
120
- <div class="card-value-row"><div class="card-value" id="statCost">-</div><div class="card-trend" id="trendCost"></div></div>
121
- <div class="card-sub" id="statCostModel"></div>
122
- </div>
123
- </section>
124
-
125
- <section class="git-section" id="gitSection" style="display:none;">
126
- <div class="cta-band-light">
127
- <h3 class="title-lg">Git 代码产出</h3>
128
- <div class="git-stats" id="gitStats"></div>
129
- <div class="git-ai-stats" id="gitAiStats"></div>
130
- </div>
131
- <div class="chart-row git-insights-row" id="gitInsightsRow" style="display:none;">
132
- <div class="chart-card">
133
- <h3 class="title-md">提交类型分布</h3>
134
- <div class="chart-wrap"><canvas id="commitTypeChart"></canvas></div>
135
- </div>
136
- <div class="chart-card">
137
- <h3 class="title-md">文件热点 Top 10</h3>
138
- <div id="fileHotspotsTable" class="hotspots-table"></div>
139
- </div>
140
- </div>
141
- </section>
142
-
143
- <section id="analyticsSection">
144
- <div class="section-header">
145
- <h2 class="title-md">数据分析</h2>
146
- </div>
147
- <div class="no-data-hint" id="noDataHint" style="display:none;">
148
- <p>该时间段暂无使用数据</p>
149
- </div>
150
- <div class="charts-dashboard" id="chartsDashboard">
151
- <section class="charts-section">
152
- <div class="chart-row">
153
- <div class="chart-card">
154
- <h3 class="title-md">工作类型分布</h3>
155
- <div class="chart-wrap"><canvas id="scenarioChart"></canvas></div>
156
- </div>
157
- <div class="chart-card">
158
- <h3 class="title-md">模型使用分布</h3>
159
- <div class="chart-wrap"><canvas id="modelChart"></canvas></div>
160
- </div>
161
- </div>
162
- <div class="chart-row">
163
- <div class="chart-card">
164
- <h3 class="title-md">项目使用分布</h3>
165
- <div class="chart-wrap"><canvas id="projectChart"></canvas></div>
166
- </div>
167
- <div class="chart-card">
168
- <h3 class="title-md">工具调用排行</h3>
169
- <div class="chart-wrap"><canvas id="toolChart"></canvas></div>
170
- </div>
171
- </div>
172
- </section>
173
- <section class="trend-section" id="trendSection" style="display:none;">
174
- <div class="chart-card trend-card">
175
- <h3 class="title-md">使用趋势</h3>
176
- <div class="chart-wrap chart-wrap-tall"><canvas id="trendChart"></canvas></div>
177
- </div>
178
- </section>
179
- <section class="trend-section" id="cacheSection" style="display:none;">
180
- <div class="chart-card">
181
- <h3 class="title-md">缓存效率</h3>
182
- <div class="chart-wrap"><canvas id="cacheChart"></canvas></div>
183
- </div>
184
- </section>
185
- <section class="trend-section" id="modelCostSection" style="display:none;">
186
- <div class="chart-card">
187
- <h3 class="title-md">模型费用分布</h3>
188
- <div class="chart-wrap chart-wrap-tall"><canvas id="modelCostChart"></canvas></div>
189
- </div>
190
- </section>
191
- </div>
192
- </section>
193
-
194
- <section class="welcome-page" id="welcomePage" style="display:none;">
195
- <div class="welcome-content">
196
- <div class="welcome-brand">
197
- <svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-bottom:16px;">
198
- <rect x="8" y="12" width="32" height="24" rx="6" stroke="#111111" stroke-width="2.5" fill="none"/>
199
- <path d="M16 22L22 28L32 18" stroke="#111111" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
200
- </svg>
201
- <h1 class="welcome-title">欢迎使用 LumenCode</h1>
202
- <p class="welcome-subtitle">AI 编码助手使用统计与代码产出分析工具</p>
203
- </div>
204
-
205
- <div class="welcome-features">
206
- <div class="feature-item">
207
- <svg class="feature-icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
208
- <rect x="3" y="3" width="18" height="18" rx="2"/>
209
- <path d="M3 9h18M9 21V9"/>
210
- </svg>
211
- <div class="feature-text">
212
- <h4>Token 消耗追踪</h4>
213
- <p>按日/周/月统计输入、输出、缓存命中</p>
214
- </div>
215
- </div>
216
- <div class="feature-item">
217
- <svg class="feature-icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
218
- <circle cx="12" cy="12" r="9"/>
219
- <path d="M12 6v6l4 2"/>
220
- </svg>
221
- <div class="feature-text">
222
- <h4>费用估算</h4>
223
- <p>基于模型定价自动计算成本</p>
224
- </div>
225
- </div>
226
- <div class="feature-item">
227
- <svg class="feature-icon-svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
228
- <path d="M12 2L2 7l10 5 10-5-10-5z"/>
229
- <path d="M2 17l10 5 10-5"/>
230
- <path d="M2 12l10 5 10-5"/>
231
- </svg>
232
- <div class="feature-text">
233
- <h4>AI 贡献度</h4>
234
- <p>关联 Git 提交,量化 AI 辅助占比</p>
235
- </div>
236
- </div>
237
- </div>
238
-
239
- <div class="welcome-steps">
240
- <div class="step-card">
241
- <div class="step-header">
242
- <span class="step-number">1</span>
243
- <h3>选择 Claude 日志目录</h3>
244
- </div>
245
- <p class="step-desc">Claude Code 会话日志的存放路径,通常是 <code>~/.claude</code></p>
246
- <label for="welcomeClaudeDir" class="sr-only">Claude 日志目录</label>
247
- <input type="text" class="welcome-input" id="welcomeClaudeDir" placeholder="例如: C:/Users/xxx/.claude" />
248
- </div>
249
-
250
- <div class="step-card">
251
- <div class="step-header">
252
- <span class="step-number">2</span>
253
- <h3>选择项目仓库(可选)</h3>
254
- </div>
255
- <p class="step-desc">用于关联 Git 代码产出统计,多个仓库用逗号分隔</p>
256
- <label for="welcomeRepos" class="sr-only">项目仓库路径</label>
257
- <input type="text" class="welcome-input" id="welcomeRepos" placeholder="例如: D:/project1, D:/project2" />
258
- </div>
259
- </div>
260
-
261
- <div class="welcome-actions">
262
- <button class="btn-primary welcome-start-btn" id="welcomeStartBtn">开始使用</button>
263
- <p class="welcome-hint" id="welcomeHint"></p>
264
- </div>
265
- </div>
266
- </section>
267
-
268
- <section class="work-report-section" id="workReportSection" style="display:none;">
269
- <div class="chart-card">
270
- <div class="work-report-header">
271
- <h3 class="title-md">工作汇报</h3>
272
- <div class="work-report-actions">
273
- <div class="level-tab-group">
274
- <button class="level-tab active" data-level="detailed">详报</button>
275
- <button class="level-tab" data-level="brief">简报</button>
276
- </div>
277
- <div class="platform-pill-group">
278
- <button class="platform-tab active" data-platform="default">标准</button>
279
- <button class="platform-tab" data-platform="feishu">飞书</button>
280
- <button class="platform-tab" data-platform="dingtalk">钉钉</button>
281
- </div>
282
- <span class="action-divider"></span>
283
- <button id="copyWorkReport" class="btn-secondary">复制</button>
284
- <button id="downloadMdBtn" class="btn-secondary">下载 .md</button>
285
- <button id="backToReport" class="btn-primary">返回</button>
286
- </div>
287
- </div>
288
- <div id="workReportContent" class="work-report-content"></div>
289
- </div>
290
- </section>
291
- <!-- Drill-down Modal -->
292
- <div id="drillModal" class="modal" style="display:none;">
293
- <div class="modal-backdrop"></div>
294
- <div class="modal-panel" style="max-width:640px;">
295
- <div class="modal-header">
296
- <h3 class="title-md" id="drillTitle">明细</h3>
297
- <button id="closeDrill" class="icon-btn"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
298
- </div>
299
- <div class="modal-body" id="drillBody"></div>
300
- </div>
301
- </div>
302
- </main>
303
- </div>
304
-
305
- <!-- Settings Modal -->
306
- <div id="settingsModal" class="modal" style="display:none;">
307
- <div class="modal-backdrop"></div>
308
- <div class="modal-panel">
309
- <div class="modal-header">
310
- <h3 class="title-md">配置</h3>
311
- <button id="closeSettings" class="icon-btn"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg></button>
312
- </div>
313
- <div class="modal-body">
314
- <div class="form-group">
315
- <label class="form-label">Claude 日志目录</label>
316
- <input type="text" id="cfgClaudeDir" class="text-input form-input">
317
- </div>
318
- <div class="form-group">
319
- <label class="form-label">本地项目路径(每行一个)</label>
320
- <textarea id="cfgRepos" class="text-input form-textarea" rows="3"></textarea>
321
- </div>
322
- <div class="form-group">
323
- <label class="form-label">排除项目(每行一个)</label>
324
- <textarea id="cfgExclude" class="text-input form-textarea" rows="3"></textarea>
325
- </div>
326
- <div class="form-group">
327
- <label class="form-label">场景关键词</label>
328
- <textarea id="cfgKeywords" class="text-input form-textarea" rows="5"></textarea>
329
- <p class="form-hint">JSON 格式,如 { "coding": ["实现", "开发"] }</p>
330
- </div>
331
- </div>
332
- <div class="modal-footer">
333
- <button id="saveSettings" class="btn-primary">保存</button>
334
- </div>
335
- </div>
336
- </div>
337
-
338
- <footer class="footer">
339
- <div class="footer-inner">
340
- <p>LumenCode · AI 编码助手使用统计</p>
341
- <p class="muted-soft">数据来自本地日志,不上传至任何服务器</p>
342
- </div>
343
- </footer>
344
-
345
- <script type="module" src="/app.js"></script>
346
- </body>
347
- </html>
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>