123 lines
6.0 KiB
Markdown
123 lines
6.0 KiB
Markdown
## Context
|
||
|
||
当前 Dashboard 使用 `TargetTable` + `TargetRow` + `TargetDetail` 的表格布局,所有目标扁平排列在同一个表格中,点击行展开内联详情面板。前端组件结构为:
|
||
|
||
```
|
||
App → SummaryCards(4) + TargetTable → TargetRow → TargetDetail(内联)
|
||
```
|
||
|
||
后端 API 提供 `GET /api/targets` 返回含 `sparkline: number[]` 的目标列表,`GET /api/targets/:id/trend?hours=24` 返回趋势数据,`GET /api/targets/:id/history?limit=20` 返回历史记录。全局汇总含 `avgDurationMs`。
|
||
|
||
本次重构涉及全栈变更:YAML 配置格式、后端数据存储、API 接口、前端组件和样式。
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:**
|
||
|
||
- 引入 target 分组概念,按组展示卡片,default 组排最前
|
||
- 卡片内同时展示状态条(UP/DOWN 可视化)和迷你 sparkline(耗时趋势)
|
||
- 模态框提供丰富的详情查看体验:多维统计图 + 带分页的检查结果列表
|
||
- 模态框支持自定义时间范围筛选(分钟精度)和快捷时间范围按钮
|
||
- 移除无实际意义的全局平均耗时统计
|
||
- 统一卡片迷你可视化的采样数量为全局可配置项 `recentSampleCount`
|
||
- 不引入新依赖,复用现有 recharts 库
|
||
|
||
**Non-Goals:**
|
||
|
||
- 分组折叠/展开功能
|
||
- 分组排序自定义(固定为 default 最前,其余按 YAML 出现顺序)
|
||
- per-target 的 sparkline 数量自定义(统一使用全局配置)
|
||
- 模态框内的状态筛选(仅支持时间范围筛选)
|
||
- 卡片内显示可用率数字
|
||
- 按耗时阈值筛选
|
||
|
||
## Decisions
|
||
|
||
### D1: group 配置采用扁平字段(方案 A)
|
||
|
||
**选择**: 在每个 target 上加 `group?: string` 可选字段。
|
||
|
||
**替代方案**: 嵌套结构(`targets: [{ group: "x", items: [...] }]`)。
|
||
|
||
**理由**: 扁平字段是增量变更,完全向后兼容,不破坏现有 targets 数组格式。嵌套结构会改变整个配置文件的顶层结构,影响面大且无额外收益。
|
||
|
||
### D2: sparkline 替换为 recentSamples 结构化数据
|
||
|
||
**选择**: 将 `sparkline: number[]` 替换为 `recentSamples: RecentSample[]`,每个 sample 包含 `timestamp`、`durationMs`、`up`。
|
||
|
||
**替代方案**: 新增独立的 status-bar API。
|
||
|
||
**理由**: 合并为一个接口减少请求数,前端一次数据同时满足状态条和 sparkline 两种可视化。`timestamp` 的包含使得 hover tooltip 有意义。
|
||
|
||
### D3: recentSampleCount 固定为 30
|
||
|
||
**选择**: StatusBar 和 MiniSparkline 的采样数量硬编码为 30。
|
||
|
||
**理由**: 30 是合理的默认值,覆盖最近 30 次检查,无需暴露配置项增加复杂度。
|
||
|
||
### D4: 模态框时间筛选同时支持快捷按钮和自定义日期选择器
|
||
|
||
**选择**: 快捷按钮(1h/6h/24h/7d)与分钟精度日期选择器并存,联动设计——点击快捷按钮自动填入日期,手动修改日期则快捷按钮取消高亮。
|
||
|
||
**理由**: 快捷按钮覆盖绝大多数场景,日期选择器提供精确控制能力。分钟精度对于拨测监控场景足够精确。
|
||
|
||
### D5: trend API 改用 from/to 时间范围参数
|
||
|
||
**选择**: `GET /api/targets/:id/trend?from=ISO&to=ISO` 替代 `?hours=24`。
|
||
|
||
**理由**: 模态框支持自定义时间范围,hours 参数无法表达任意时间范围。from/to 是更通用的设计。
|
||
|
||
### D6: history API 新增分页支持
|
||
|
||
**选择**: `GET /api/targets/:id/history?from=ISO&to=ISO&page=1&pageSize=20`,返回 `{ items, total, page, pageSize }`。
|
||
|
||
**理由**: 自定义时间范围可能导致大量数据(如选择 7 天范围),分页避免一次性传输过多数据。
|
||
|
||
### D7: SummaryCards 从 4 个减为 3 个
|
||
|
||
**选择**: 移除"平均耗时"卡片,保留"全部/正常/异常"。
|
||
|
||
**理由**: 引入分组后,不同分组目标的平均耗时混合计算没有实际参考价值。具体目标的耗时信息在模态框中查看。
|
||
|
||
### D8: targets 表使用 grp 列名
|
||
|
||
**选择**: 数据库列名使用 `grp` 而非 `group`。
|
||
|
||
**理由**: `group` 是 SQL 关键字,使用 `grp` 避免转义问题。API 层和前端仍使用 `group` 作为字段名。
|
||
|
||
### D9: 卡片固定宽度 280px + CSS Grid auto-fill 响应式
|
||
|
||
**选择**: `grid-template-columns: repeat(auto-fill, 280px)` 实现响应式布局。
|
||
|
||
**替代方案**: 百分比宽度或 flex-wrap。
|
||
|
||
**理由**: 固定宽度保证卡片内容一致性,auto-fill 自动适应视口宽度变化,从 1 列到多列无缝适配。
|
||
|
||
### D10: 分组排序由后端 SQL 保证
|
||
|
||
**选择**: `ORDER BY CASE WHEN grp='default' THEN 0 ELSE 1 END, grp, id`。
|
||
|
||
**理由**: 后端排序后前端只需顺序遍历渲染,无需额外排序逻辑。分组名按 YAML 首次出现顺序(即 id 顺序)自然排序。
|
||
|
||
### D11: 环形图(Donut Chart)展示状态分布
|
||
|
||
**选择**: 模态框统计图使用 recharts 的 PieChart + 内部标签实现环形图,中间显示可用率百分比。
|
||
|
||
**替代方案**: 纯饼图。
|
||
|
||
**理由**: 环形图中间可展示关键数字(可用率 %),信息密度更高。
|
||
|
||
### D12: 状态条使用连续色块
|
||
|
||
**选择**: 方块数量固定 30 个,每个 6px 宽 2px 间距,UP 绿色 `#1fbf75`,DOWN 红色 `#e5484d`,无数据灰色 `#e2e8f0`。
|
||
|
||
**理由**: 类似 GitHub contribution graph 的可视化方式,直观展示最近检查状态。
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- [卡片信息密度] 卡片宽度仅 280px,同时放状态条和 sparkline 可能显得拥挤 → 状态条和 sparkline 各占一行,垂直堆叠,控制高度在合理范围
|
||
- [API BREAKING 变更] sparkline → recentSamples、trend hours → from/to、history limit → page/pageSize 均为不兼容变更 → 项目未上线无需向前兼容,一次性完成
|
||
- [targets 表 schema 变更] 新增 grp 列需要数据库 migration → SQLite ALTER TABLE ADD COLUMN 是安全操作,新列有默认值不影响已有数据
|
||
- [模态框复杂度] 时间选择器 + 分页 + 多图表实现复杂度较高 → 拆分为独立子组件,每个组件职责单一
|
||
- [recentSampleCount 默认值] 固定为 30,无法通过配置调整 → 合理值,30 覆盖足够长的最近检查周期
|