1. 趋势可视化升级(方案 A):
- 新增 TrendLineChart 组件(自绘 SVG 折线图,无第三方依赖)
- 每日/月度趋势从纯表格升级为面积折线图,默认图表视图
- 数据补零 + 超过 90 天自动按周降采样
- 统计摘要:峰值/均值/合计/环比,均值参考线,峰值标注
- hover tooltip + 视图切换(图表/表格),表格视图完整保留
- 修复 P1-2:每日趋势标题写死'近31天'改为动态显示真实天数
- 表格视图去掉 .slice(-31) 截断,显示完整范围
2. 部署脚本 git-incremental-deploy.ps1 stderr bug 修复:
- PowerShell 在 ErrorActionPreference=Stop 下把 git/plink 的 stderr
提示当致命错误,导致部署在 Git Sync 阶段误中断
- 在原生程序调用局部作用域改为 Continue,真实错误仍由 LASTEXITCODE 捕获
11 KiB
数据统计页 · 趋势可视化升级 设计提案
创建时间:2026-06-27 范围:仅
components/admin/DataStatisticsTab.tsx的趋势展示区 + 必要的后端口径微调 原则:只做加法和体验升级,不删任何现有功能;不改数据库、不动业务逻辑
1. 现状诊断(已通过代码摸底确认)
1.1 趋势区当前形态
┌─ 每日趋势(近31天)─────┐ ┌─ 月度趋势 ─────────────┐
│ 纯 <table> 表格 │ │ 纯 <table> 表格 │
│ 日期 | 上传数 │ │ 月份 | 上传数 │
│ 2026-06-01 | 12 │ │ 2026-01 | 320 │
│ 2026-06-02 | 8 │ │ 2026-02 | 410 │
│ ...(最多31行,可滚动) │ │ ...(可滚动) │
└──────────────────────────┘ └──────────────────────────┘
问题:
- 信息密度低:纯表格,看不出趋势走向(涨/跌/峰值/低谷),需要肉眼逐行比对数字
- 缺对比基准:只看到绝对值,不知道"这个数是高还是低"——没有环比/同比/均值线
- P1-2 bug:每日趋势标题写死"近31天",但数据实际是后端按筛选时间范围返回的日期桶,选"全部"时表格可能是几年前的31天,标题与数据口径不符
- 交互弱:不能hover看明细、不能缩放、点击日期不能联动其它图表
1.2 数据基础(已确认)
后端 lib/admin-material-stats.ts 返回的趋势数据:
dailyUploads: { bucket: '2026-06-01', count: number }[] // 按筛选范围内的天
monthlyUploads: { bucket: '2026-06', count: number }[] // 按筛选范围内的月
数据已经是干净的时序数组,无需后端改动即可做折线图。唯一的口径问题是 dailyUploads 只返回"有数据的天"(稀疏),绘图时需要补零。
1.3 技术约束
- 项目无图表库(recharts/d3/echarts 都没装),现有柱状图是手写
div + height% - 引入新库 = 增加 bundle 体积 + 构建依赖。需权衡"自己画 SVG"vs"引库"
2. 设计目标
- 一眼看出趋势:用折线/面积图替代表格,涨跌、峰值、低谷立刻可见
- 提供对比基准:加环比(vs 上一周期)、移动平均线,让数字有参照系
- 修复 P1-2:每日趋势标题与数据口径一致
- 保持轻量:不引入重量级图表库,自己用 SVG 画(与现有柱状图风格一致)
- 可降级:表格作为辅助视图保留(切换"图表/表格"),照顾想看精确数字的场景
3. 提案:三档方案(成本递增,任选一档)
方案 A:最小改动(推荐先做)
成本:约 1 个前端组件 + 0 后端改动
把"每日趋势"和"月度趋势"两个表格,各替换为自绘 SVG 折线/面积图,并保留一个"切换表格视图"的按钮。
每日趋势 [📈 图表] [📊 表格] ← 切换
┌──────────────────────────────────────────────────────────────┐
│ ╱╲ ╱╲ │
│ ╱╳╯ ╲ ╱ ╲ ╱╲ ← 面积折线(sky 渐变填充) │
│ ╱ ╲__╱ ╲___╱ ╲___ │
│ ─────────── 均值线(虚线)───────────────── │
│ 06-01 06-10 06-20 06-30 ← x轴 │
│ 峰值 06-08 (42条) · 均值 18.3条/天 · 合计 549条 │ ← 统计摘要
└──────────────────────────────────────────────────────────────┘
hover 任意点 → tooltip 显示 "2026-06-08:42 条"
新增信息(表格完全没有的):
- 📍 峰值日期标注(哪天最高)
- 📍 均值参考线(虚线,一眼判断高低)
- 📍 统计摘要条(峰值/均值/合计/环比%)
- 📍 hover tooltip(精确值)
修复 P1-2:标题动态显示真实范围,如"每日趋势(2026-06-01 ~ 2026-06-27,共27天)"。
方案 B:中等改动(A + 同比对比)
成本:A + 前端补零逻辑 + 可能的后端口径微调
在方案 A 基础上,给月度趋势加同比折线(今年 vs 去年同期):
月度趋势(含同比)
┌────────────────────────────────────────────────┐
│ ─── 今年(实线) │
│ ┄┄┄ 去年同期(虚线) ← 需后端返回去年同期数据│
│ 1月 2月 3月 4月 5月 6月 │
│ 环比 +12.3% 同比 +5.1% │
└────────────────────────────────────────────────┘
后端改动(可选):getMaterialUploadStats 增加 previousMonthlyUploads(取筛选范围向前平移一年的同长度区间)。不改表结构,只多一次聚合查询。
方案 C:大改动(B + 交互联动)
成本:B + 图表点击联动 + 时间粒度切换
- 点击折线上某月 → 自动把上方"部门/素材类型分布"切换到该月范围
- 加"日/周/月"粒度切换器(当前只有日和月两张表)
- 区域选择缩放(拖选一段时间放大看)
4. 推荐落地路径
强烈建议先做方案 A,理由:
| 维度 | 方案 A | 方案 B | 方案 C |
|---|---|---|---|
| 视觉提升 | ★★★★ 大 | ★★★★★ 很大 | ★★★★★ 很大 |
| 信息增量 | 中(均值/峰值/摘要) | 高(同比) | 很高(联动) |
| 后端改动 | 0 | 小(多一次聚合) | 中 |
| 新代码量 | ~250 行(1个SVG组件) | +100 行 | +300 行 |
| bundle 体积 | 0(自己画SVG) | 0 | 0 |
| 回归风险 | 低(纯展示层) | 中(碰后端) | 高(联动状态多) |
| 用户感知 | 立竿见影 | 需有去年数据才显价值 | 依赖使用习惯 |
方案 A 的性价比最高:零后端风险、零依赖、视觉提升立竿见影。做完 A 看实际效果,再决定要不要追加 B/C。
5. 方案 A 详细技术设计
5.1 新增组件:TrendLineChart
位置:components/admin/TrendLineChart.tsx(独立出来,便于复用和测试)
Props:
interface TrendPoint { bucket: string; count: number }
interface TrendLineChartProps {
data: TrendPoint[] // 后端返回的 dailyUploads / monthlyUploads
granularity: 'day' | 'month' // 决定 x 轴标签格式和补零策略
accent: 'sky' | 'teal' // 与现有柱状图配色呼应
startDate?: string // 用于动态标题和补零范围
endDate?: string
}
5.2 SVG 折线图核心算法
1. 数据补零:把 data 按 [startDate, endDate] 补齐成连续日期序列
(后端只返回有数据的天,绘图需要连续 x 轴)
- day: 按天补,跨度大时自动降采样到"每周一个点"
- month: 按月补
2. 坐标映射:
- x = (index / (n-1)) * width
- y = height - (count / maxCount) * height
3. 路径生成:
- 折线: M x0,y0 L x1,y1 ...
- 面积: 折线 + 回到底边的闭合路径,fill 用渐变(opacity 0.15→0)
4. 均值参考线:
- avg = sum(count) / n
- y = height - (avg / maxCount) * height
- 虚线 stroke-dasharray="4 4"
5. 峰值标注:
- 找 max count 的点,上方画圆点 + 文字标签
6. hover tooltip:
- 监听 mousemove,找最近的数据点,浮层显示 "日期:N条"
5.3 统计摘要条(图表上方)
峰值 06-08(42条) · 均值 18.3条/天 · 合计 549条 · 环比 +12.3% ▲
- 峰值/均值/合计:前端从 data 算
- 环比:对比"后半段 vs 前半段"的均值变化(无需后端,纯前端切分)
5.4 视图切换
图表右上角 [📈 图表] [📊 表格] 切换按钮(用现有 rounded-apple 风格)。
- 默认图表视图
- 切到表格视图 = 当前形态(保留,零删减,满足"都不删")
5.5 标题修复(P1-2)
// 修改前(写死):
<h3>每日趋势(近31天)</h3>
// 修改后(动态):
const dayCount = dailyUploads.length
const rangeText = startDate && endDate
? `${startDate} ~ ${endDate},共${dayCount}天`
: `全部时间,共${dayCount}天`
<h3>每日趋势(${rangeText})</h3>
6. 配色与视觉规范(对齐已完成的 UI 重做)
延续上一轮 UI 重做的 Apple 基线:
- 折线/面积主色:
sky-500(每日)/teal-500(月度),与两个柱状图呼应 - 面积填充:
from-sky-500/20 to-transparent渐变 - 均值线:
gray-400虚线 - 峰值点:
sky-600实心圆 + 白色描边 - tooltip:
rounded-apple白底 +shadow-apple-lg - 字体:
tabular-nums(数字等宽对齐)
7. 改动清单(方案 A)
| 文件 | 改动 | 风险 |
|---|---|---|
components/admin/TrendLineChart.tsx |
新增(~250行 SVG 折线组件) | 低,新文件 |
components/admin/DataStatisticsTab.tsx |
引入 TrendLineChart,替换两个趋势表格的渲染,加视图切换按钮,修 P1-2 标题 | 低,只动渲染层 |
后端 lib/admin-material-stats.ts |
不改 | - |
| 数据库 / Prisma | 不改 | - |
不涉及:接口签名、响应结构、权限、数据写入、其它页面。
8. 验证清单(做完后)
npx tsc --noEmit类型通过npm test现有测试不回归- 切换"今天/近7天/近30天/本月/上月/全部"6个预设,图表正确补零、标题正确显示
- 表格视图切换正常,数据与图表一致
- hover tooltip 正确显示日期和数值
- 峰值/均值/合计/环比 4 个摘要数字计算正确
- shadow 环境实测视觉
9. 待你确认的开放问题
- 方案选 A / B / C?(我推荐 A)
- 视图切换默认显示图表还是表格?(我推荐默认图表)
- 每日趋势跨度很大时(比如选"全部",跨2年=730天),怎么处理?
- 选项:(a) 自动降采样到每周一个点 (b) 横向滚动 (c) 强制只显示最近N天
- 我推荐 (a) 降采样,保证图表可读
- 要不要这个提案先作为文档存档,等你 review 后再决定是否实施?