ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

qwen-code 统计仪表盘重构实战:Activity / Efficiency 双 Tab 的设计、数据层扩展与源码实现

2026/9/11 23:09:09 拓冰建站 浏览量
qwen-code 统计仪表盘重构实战:Activity / Efficiency 双 Tab 的设计、数据层扩展与源码实现 qwen-code 统计仪表盘重构实战Activity / Efficiency 双 Tab 的设计、数据层扩展与源码实现【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code导读本文以 qwen-code 开源仓库中的 Stats Dashboard Redesign 设计规格 为核心骨架系统讲解 TUI 中/stats统计仪表盘的重构方案如何把原有的 Overview / Models 双 Tab 重构为 Session / Activity / Efficiency 三 Tab如何引入时间范围选择与环比 Delta 指标以及如何在不破坏旧数据的前提下扩展usage_record.jsonl的数据模型。读完本文你将掌握这套仪表盘从规格设计、数据结构演进到键盘交互与热力图渲染的完整实现路径并能直接对照仓库源码进行二次开发或移植。一、重构目标与总体设计规格文档2025-06-03-stats-dashboard-redesign.md定义了本次重构的核心目标重新设计/statsTUI 仪表盘改进布局层级新增效率指标、工具使用明细与趋势对比能力同时保持 Session 标签页原样不动。重构后的标签页结构如下Tab 1: Session 不变——实时当前会话指标 Tab 2: Activity 基于时间的趋势与使用模式 Tab 3: Efficiency 性能指标与工具分析在仓库源码中这一结构已经落地。查看 StatsDialog.tsx 可以看到三个标签页组件被分别拆分为独立的SessionTab、ActivityTab、EfficiencyTab由StatsDialog统一调度TAB_DEFS来自stats-helpers.js定义了 Tab 枚举与循环切换顺序。StatsDialog内部还通过handleTabChange实现了Tab/ShiftTab的循环切换(idx direction TAB_DEFS.length) % TAB_DEFS.length保证焦点不会在边界卡死。值得注意的是StatsDialog还支持嵌入模式availableHeight属性当它被嵌入到设置对话框的 Stats 页时通过EFFICIENCY_CHROME_ROWS 24、MAX_EMBEDDED_TOOL_ROWS 5、CODE_IMPACT_ROWS 1等常量精确预算高度防止模型表溢出宿主视图——这是规格文档之外、源码中体现的工程细节。二、时间范围选择器与环比 Delta 计算2.1 范围切换机制所有 Activity 与 Efficiency 标签页的数据都受同一个时间范围约束通过按r键循环切换Today → Week → Month → All在 StatsDialog.tsx 中r键处理逻辑为setRangeIndex((i) (i 1) % RANGE_CYCLE.length)即对RANGE_CYCLE数组取模循环range状态驱动loadStatsData(range, liveRecord)重新加载数据useEffect依赖[range, stats.sessionId]即只在范围或会话变化时重载而不是每次指标 tick 都刷新。对话框底部的RangeIndicator会高亮当前选中的范围boldunderline accent 色并用·分隔各选项。2.2 Delta 环比规则每个 KPI 卡片都会显示一个趋势箭头将当前范围与上一个等价范围对比范围对比基准Today今天 vs 昨天Week最近 7 天 vs 前 7 天Month最近 30 天 vs 前 30 天All不显示 Delta显示规则正向变化用绿色▲ 12%负向变化用红色▼ -3%。唯独延迟Latency例外——越低越好因此颜色取反。实现路径从usage_record.jsonl加载两个时间片分别聚合后计算百分比变化。规格文档建议的 delta 字段在 statsDataService.ts 的StatsData接口中已完整落地delta对象包含sessions、duration、tokens、cacheRate、toolSuccess、avgLatency六个number | null字段——null即表示该范围下无上一周期可比数据如all范围。三、Activity 标签页时间维度下的使用趋势Activity 页自上而下分为四块KPI 行、GitHub 风格热力图、Token 趋势折线图、项目排行榜。3.1 KPI 行三个横向排列的指标卡每个都带数值 Delta 箭头指标数据来源示例Sessionsreport.sessionCount42 ▲8Durationreport.totalDurationMs18h 32m ▲2hTokens求和report.models[*].totalTokens2.4m ▲12%其中 Duration 的展示会自动格式化为人性化时长小时/分钟Tokens 则缩写成2.4m这样的紧凑形式。3.2 GitHub 风格热力图全宽渲染网格布局仿 GitHub contribution graph颜色强度 每日总 Token 消耗注意不是会话数今天的格子有特殊边框或标记字符如用[ ]而非 或更亮的描边色右侧对齐元信息streak: 12d │ best: 23d图例行Less ░░░░░ More列标签显示月份缩写 日期数字行标签为 Mon / Wed / Fri紧凑 3 行模式展示周数由终端宽度自适应min(26, max(8, floor((bodyWidth - 4) / 2)))。这段公式在 StatsDialog.tsx 有对应实现safeWidth Math.max(72, width ?? 100)bodyWidth safeWidth - 6宽度下限被钳制在 72 列保证窄终端下布局不崩。源码印证statsDataService.ts 中的buildHeatmap以YYYY-MM-DD为 key对每条记录内所有模型的totalTokens缺失时回退为inputTokens outputTokens thoughtsTokens求和产出Recordstring, number——确认热力图数值语义就是“每日总 Token”。Streak连续使用天数的计算在 statsDataService.ts 的calculateStreaks中实现将日期去重排序后逐日比对diff 1则当前 streak 累加diff 1则重置若最后一条数据距今超过 1 天当前 streak 归零从而同时得出currentStreak与longestStreak。3.3 Token 趋势折线图使用仓库既有的buildLineChartData生成 Braille 子像素折线图单一序列每日总 Token高度 6 行当范围为all时可用←/→按月翻页导航月份标签形如← Jun 2025 →。月导航的逻辑在 StatsDialog.tsx←/h把chartMonthOffset递增最多到months.length - 1months 由data.tokensPerDay中所有date.slice(0, 7)去重得出→/l递减最小为 0并且仅当activeTab activity range all时生效——与规格完全一致。3.4 项目排行榜展示 Top 5 项目数据源为report.projects按totalTokens降序排列Project Sessions Tokens Duration qwen-code 28 1.8m 12h web-app 10 420k 4h infra 4 180k 2h四、Efficiency 标签页性能与工具效率分析Efficiency 页自上而下分为四块性能卡片行、工具排行榜、模型对比表、代码影响。4.1 性能卡片行三个盒式指标卡指标计算公式数据来源Cache Hit RatecachedTokens / inputTokens * 100report.models[*].cachedTokens/inputTokensTool Success RatetotalSuccess / totalCalls * 100report.tools.totalSuccess/totalCallsAvg LatencytotalLatencyMs / totalRequests持久化记录中的totalLatencyMs或按模型数据计算每个卡片展示标签、加粗数值/百分比、Delta 箭头。关于 Avg Latency 的关键设计决策重构前UsageSummaryRecord并不持久化延迟数据规格文档给出了两个候选方案——仅从实时SessionMetrics计算当前会话延迟历史数据一律显示—为持久化记录新增totalLatencyMs字段旧记录迁移后显示—。最终决策方案 2——扩展UsageSummaryRecord增加可选的totalLatencyMs字段旧记录因缺少该字段延迟 Delta 显示—。源码印证这一决策已完全落地。usageHistoryService.ts 中UsageSummaryRecord接口包含可选字段totalLatencyMs?: number且tools.byName中每个工具的聚合也带totalDurationMs?: number见第 61-64 行AggregatedReport则进一步把延迟与工具耗时升级为必填顶层totalLatencyMs: number、每个模型的totalLatencyMs: number、topTools数组元素包含totalDurationMs: number见第 86-117 行——说明数据层在聚合阶段已统一补齐默认值UI 层无需再判空。规格文档中“当前topTools只有 count/success/fail需要为聚合增加totalDurationMs”的备注在源码中同样已经解决。4.2 工具排行榜按调用次数展示 Top 8 工具Tool Calls Time Success edit 847 42.3s ██████████ 98% read 612 8.1s ██████████ 99% bash 431 67.8s █████████░ 89% glob 298 2.4s ██████████ 99% grep 256 3.1s █████████░ 97% write 189 12.5s ██████████ 96% agent 45 89.2s ████████░░ 82%成功率用 10 字符条形图可视化实心█ 空心░颜色规则≥95% 绿色≥80% 橙色80% 红色数据源report.tools.topTools聚合时补充了 duration。该表格的数据结构在 statsDataService.ts 的StatsData.toolLeaderboard中定义为{ name, count, totalDurationMs, successRate }与规格文档的数据契约完全一致。4.3 模型对比表Model Reqs In/Out Cache Latency ● qwen-max 186 1.2m/340k 91% 2.1s ● qwen-plus 124 890k/210k 84% 1.2s ● qwen-turbo 67 310k/89k 72% 0.8s按totalTokens降序排列系列色圆点标识●Cache 列颜色规则≥85% 绿色≥70% 橙色70% 红色数据源report.models。Efficiency 页的模型表在嵌入模式下还会受到行数上限约束maxModelRows高度预算由 StatsDialog.tsx 动态计算从availableHeight中减去固定的 chrome 行数24、工具排行榜占用的行数含截断时的N more提示以及 Code Impact 占用的 1 行结果下限钳制为 3 行。4.4 代码影响单行汇总数据源为report.files.linesAdded/report.files.linesRemovedCode 2,847 lines / -1,203 lines net: 1,644五、键盘控制总览按键动作Tab/ShiftTab切换标签页r循环切换范围today → week → month → all←/h上一月图表导航仅 rangeall→/l下一月图表导航仅 rangeallEsc关闭对话框这些按键全部在 StatsDialog.tsx 的useKeypress中注册并通过isFocused属性控制是否消费键盘事件嵌入模式下避免与宿主视图抢焦点。对话框底部还会根据当前 Tab 与范围动态显示快捷键提示例如 Activity 页且 rangeall 时提示tab · r dates · ←→ month · esc。六、数据层变更向后兼容的 schema 扩展6.1 UsageSummaryRecord v1 扩展在既有 schema 上仅新增可选字段保证旧记录可继续读取interface UsageSummaryRecord { // ... existing fields ... totalLatencyMs?: number; // NEW: sum of all API response latencies tools: { // ... existing fields ... byName: Recordstring, { count: number; success: number; fail: number; totalDurationMs?: number; // NEW: sum of tool execution time }; }; }对照 usageHistoryService.ts 的实际实现totalLatencyMs与byName[].totalDurationMs均已存在且UsageSummaryRecord还带version: 1版本标记与可选的skills字段——仓库对“旧记录缺字段”的处理模式是统一的所有新增字段一律 optionalUI 侧按缺省值兜底。另外usageHistoryService.ts顶部注释第 19-35 行揭示了一个重要的工程权衡LIVE_REBUILD_WINDOW_DAYS 35——把未持久化的 daemon / Web Shell / 进行中会话合并进历史时只回放最近 35 天的 transcript覆盖 month30 天范围加余量而已持久化的usage_record.jsonl记录不受此窗口限制始终全量并入从而热力图保留完整历史。这是规格文档未涉及、但直接决定“热力图能看到多久历史”的实现细节。6.2 StatsData 扩展interface StatsData { // ... existing fields ... delta?: { sessions: number | null; // percentage change duration: number | null; tokens: number | null; cacheRate: number | null; toolSuccess: number | null; avgLatency: number | null; }; efficiency: { cacheHitRate: number; toolSuccessRate: number; avgLatencyMs: number | null; }; toolLeaderboard: Array{ name: string; count: number; totalDurationMs: number; successRate: number; }; }对照 statsDataService.ts 的实现StatsData接口包含reportAggregatedReport、heatmap、currentStreak、longestStreak、tokensPerDay、delta、efficiency、toolLeaderboard全部字段其中delta已从规格的“可选”升级为结构化的| null联合类型语义更明确。6.3 热力图数据语义变更与强度标定变更前buildHeatmapData接收Recordstring, numbervalue 当日会话数变更后value 当日总 Token0-4 级强度映射需要重新标定0无使用1 10k tokens210k - 50k tokens350k - 200k tokens4 200k tokens规格同时强调阈值应基于数据分布动态计算百分位法而非硬编码以适配不同的使用模式。源码印证asciiCharts.ts 中存在intensityLevel(count, thresholds)函数说明强度分级已抽象为“给定阈值数组映射到 0-4 级”的通用逻辑支持按数据分布注入阈值。6.4 今日高亮Today HighlightbuildHeatmapData需要把今天的格子打上特殊标记。源码实现为 asciiCharts.ts通过todayKey dayKey(new Date())生成今日 key与当前格子比对得到isToday标记渲染时用更明亮的描边字符如[▓]而非▓▓突出显示——与规格文档的字符方案完全对应。七、国际化新增 i18n 键所有用户可见字符串统一包裹在t()中新增键如下stats.activity Activity stats.efficiency Efficiency stats.today Today stats.sessions Sessions stats.duration Duration stats.tokens Tokens stats.cacheHitRate Cache Hit Rate stats.toolSuccessRate Tool Success stats.avgLatency Avg Latency stats.toolLeaderboard Tool Leaderboard stats.calls Calls stats.time Time stats.success Success stats.models Models stats.reqs Reqs stats.cache Cache stats.latency Latency stats.codeImpact Code Impact stats.net net stats.streak streak stats.best best stats.tokenTrend Token Trend stats.projects Projects stats.project Project在 UI 层StatsDialog通过t((Tab to switch))、t(Loading stats...)、t(Failed to load stats. Press r to retry.)等调用印证了该模式且加载失败时提示“按 r 重试”恰好复用了范围切换键交互自洽。八、改动文件清单与源码对应规格文档列出的改动清单在仓库中的落点如下文件规格实际代码位置变更内容StatsDialog.tsxpackages/cli/src/ui/components/StatsDialog.tsx以SessionTab/ActivityTab/EfficiencyTab替换原 Overview / Models承载 Tab 切换、范围循环、月导航、嵌入模式高度预算usageHistoryService.tspackages/core/src/services/usageHistoryService.tsUsageSummaryRecord增加totalLatencyMs与byName[].totalDurationMsAggregatedReport增加聚合后的延迟与工具耗时statsDataService.tspackages/cli/src/ui/utils/statsDataService.tsStatsData增加delta/efficiency/toolLeaderboardbuildHeatmap改为按每日总 Token 统计新增 streak 计算asciiCharts.tspackages/cli/src/ui/utils/asciiCharts.tsintensityLevel强度映射、isToday今日高亮标记、Braille 折线图复用uiTelemetry.tspackages/core/src/telemetry/uiTelemetry.ts确保延迟数据进入持久化路径被usageHistoryService.ts引用三个标签页组件的拆分实现分别位于 StatsSessionTab.tsx、StatsActivityTab.tsx、StatsEfficiencyTab.tsx。九、明确不在本次范围内为避免范围蔓延规格明确排除了以下能力成本估算——依赖用户自配的价格体系可后续添加单文件级变更追踪——当前数据模型不支持上下文窗口用量 / 压缩指标——当前未跟踪单个会话的下钻交互——本次不实现。这些排除项也为后续演进划清了边界任何想在这四个方向扩展的开发者都需要先补齐对应的数据采集层。总结qwen-code 的/stats仪表盘重构是一套典型的“数据模型先行、UI 分层落地”的演进案例规格先敲定UsageSummaryRecord的可选字段扩展与StatsData的契约再通过r键驱动的范围循环支撑 Delta 环比最后在 TUI 层以三 Tab 结构Session / Activity / Efficiency承载热力图、Braille 趋势图、工具排行榜与模型对比表。对照仓库源码可以确认规格中的每一项决策——包括延迟持久化的方案 2、热力图按 Token 而非会话计数、今日格子高亮、强度阈值百分位化——均已实现且工程上额外处理了窄终端钳制、嵌入模式高度预算与未持久化会话的回放窗口等边界问题。对于希望深度定制统计面板或移植到其他 TUI 应用的开发者这份规格与其源码实现构成了完整的参考闭环。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考