43 KiB
43 KiB
管理后台与可视化设计文档
一、设计原则
1.1 核心理念
克制、高效、数据为先
- 不做花哨的动效,所有设计都服务于「快速定位问题」
- 深色主题为主,长时间盯着不累眼
- 信息分层明确,重要的信息一眼看到,次要的信息收起来
- 操作路径短:3 次点击以内能到达任何核心页面
1.2 技术选型
| 层级 | 技术 | 说明 |
|---|---|---|
| 框架 | React 18 | 生态成熟,社区活跃 |
| 构建 | Vite 5 | 快,开发体验好 |
| 语言 | TypeScript | 类型安全,减少 bug |
| UI 库 | Ant Design 5 | 后台管理组件最全,深色主题好 |
| 路由 | React Router v6 | 官方推荐,功能完整 |
| 状态管理 | Zustand | 轻量,比 Redux 简单太多 |
| 数据请求 | TanStack Query (React Query) | 缓存、重发、分页都有了 |
| 图表 | ECharts 5 | 功能强大,国内用得多 |
| HTTP 客户端 | Axios | 拦截器、取消请求都方便 |
| 样式 | CSS Modules + Less | 按需定制主题 |
| 代码规范 | ESLint + Prettier | 统一代码风格 |
1.3 为什么选 Ant Design
- 组件最丰富:表格、表单、弹窗、树形...后台需要的都有
- 深色主题好:AntD 5 原生支持 ConfigProvider 切换主题
- ProComponents:ProTable、ProForm 等高级组件,开发效率翻倍
- 生态成熟:遇到问题搜一下就有答案
- 设计语言统一:有自己的设计规范,不用从零定
1.3 页面清单
| 页面 | 路径 | 优先级 | 说明 |
|---|---|---|---|
| 项目列表 | /manage/ |
P0 | 项目管理(已有) |
| 项目概览 | #/overview |
P0 | 项目总览、关键指标 |
| 错误列表 | #/errors |
P0 | 错误 Issue 列表、详情 |
| 错误详情 | #/errors/:id |
P0 | 单个错误的详细分析 |
| 性能分析 | #/performance |
P1 | Web Vitals、性能趋势 |
| 网络分析 | #/network |
P2 | 接口请求统计 |
| 行为分析 | #/behavior |
P2 | PV、用户行为 |
| 告警中心 | #/alerts |
P1 | 告警规则、告警历史 |
| 日志查询 | #/logs |
P1 | Loki 原始日志查询 |
| 接入指南 | #/integration |
P0 | SDK 接入文档(已有) |
| 项目设置 | #/settings |
P1 | 项目配置、成员、采样率 |
二、设计系统
2.1 配色系统
主色调:蓝色系(专业、可信赖)
| 用途 | 颜色 | 色值 |
|---|---|---|
| 品牌主色 | 亮蓝 | #0090f9 |
| 品牌主色(悬停) | 蓝 | #1da1f2 |
| 成功 | 绿 | #26a641 |
| 警告 | 黄 | #e9c46a |
| 错误 | 红 | #e63946 |
| 信息 | 紫 | #a855f7 |
中性色(深色主题):
| 用途 | 色值 | 说明 |
|---|---|---|
| 背景(最深) | #0d1117 |
页面底色 |
| 背景(卡片) | #161b22 |
卡片、弹窗 |
| 背景(悬浮) | #21262d |
hover、选中 |
| 边框 | #30363d |
分割线、边框 |
| 文字(主) | #e6edf3 |
标题、正文 |
| 文字(次) | #8b949e |
辅助说明、时间 |
| 文字(弱) | #6e7681 |
占位符、disabled |
2.2 字体与间距
字体栈:
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
字号阶梯:
| 用途 | 大小 | 字重 |
|---|---|---|
| 页面大标题 | 24px | 600 |
| 区块标题 | 18px | 600 |
| 卡片标题 | 16px | 600 |
| 正文 | 14px | 400 |
| 辅助文字 | 12px | 400 |
间距阶梯(4px 基准):
4px / 8px / 12px / 16px / 20px / 24px / 32px / 48px
2.3 圆角与阴影
| 元素 | 圆角 | 阴影 |
|---|---|---|
| 按钮 | 6px | 无 |
| 输入框 | 6px | 无 |
| 卡片 | 8px | 无(用边框区分) |
| 弹窗 | 12px | 0 8px 24px rgba(0,0,0,0.4) |
| 下拉菜单 | 8px | 0 4px 12px rgba(0,0,0,0.3) |
三、整体布局
3.1 布局结构
┌─────────────────────────────────────────────────────────────────┐
│ Top Bar(64px) │
│ ┌──────┐ ┌──────────────┐ ┌─────────────┐ │
│ │ Logo │ │ 项目选择器 ▼ │ │ 🔔 👤 设置 │ │
│ └──────┘ └──────────────┘ └─────────────┘ │
├────────┬────────────────────────────────────────────────────────┤
│ │ │
│ Side │ Content Area │
│ Nav │ ┌──────────────────────────────────────────────────┐ │
│(64px │ │ Page Header(标题 + 操作 + 筛选) │ │
│ 展开 │ └──────────────────────────────────────────────────┘ │
│ 220px)│ ┌──────────────────────────────────────────────────┐ │
│ │ │ Metric Cards(指标卡片行) │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ ┌──────────────────────────────────────────────────┐ │
│ │ │ Charts / Tables(主内容区) │ │
│ │ │ │ │
│ │ │ │ │
│ │ └──────────────────────────────────────────────────┘ │
│ │ │
└────────┴────────────────────────────────────────────────────────┘
3.2 侧边栏(可折叠)
收起态(64px):只显示图标
📊 ← 概览
🐛 ← 错误
⚡ ← 性能
🌐 ← 网络
📈 ← 看板
🔔 ← 告警
⚙️ ← 设置
展开态(220px):图标 + 文字 + 角标
📊 概览
🐛 错误 12 ← 未解决错误数
⚡ 性能 3 ← 有性能告警
🌐 网络
📈 看板
🔔 告警 5 ← 未读告警
⚙️ 设置
3.3 顶部栏
┌─────────────────────────────────────────────────────────────┐
│ ◀▶ 🪲 Light-Sentry [▼ 前端项目 - my-app ] 🔔 ⚙️ │
└─────────────────────────────────────────────────────────────┘
- 左侧:折叠按钮 + Logo + 产品名
- 中间:项目选择器(下拉,可搜索)
- 右侧:告警铃(有未读红点) + 设置
3.4 页面头(每个页面都有)
┌─────────────────────────────────────────────────────────────┐
│ 错误 Issues [时间范围: 24h ▼] [搜索] │
│ 12 个未解决 · 3 个今日新增 [导出] [刷新] │
└─────────────────────────────────────────────────────────────┘
四、核心页面详细设计
4.1 概览页(Overview)
定位:一屏看完项目健康状况,有问题快速跳转到对应页面
┌─────────────────────────────────────────────────────────────────┐
│ 概览 [24h ▼] [环境: 全部 ▼] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 错误数 │ │ 错误率 │ │ 影响用户│ │ LCP P95 │ │ CLS P95 │ │
│ │ 128 │ │ 2.3% │ │ 1,234 │ │ 3.2s │ │ 0.15 │ │
│ │ ↑15% │ │ ↑0.8% │ │ ↑12% │ │ 🔴 差 │ │ 🟡 中 │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ ┌──────────────────────────┐ ┌───────────────────────────────┐ │
│ │ 错误趋势(24h) │ │ Top 5 错误 │ │
│ │ ╱╲ │ │ 1. TypeError: Cannot read... │ │
│ │ ╱ ╲ ╱╲ │ │ 2. AxiosError: 500 Inter... │ │
│ │ ╱╲╱ ╲╱ ╲ │ │ 3. ReferenceError: x is ... │ │
│ │ │ │ 4. ChunkLoadError: Loadin... │ │
│ │ │ │ 5. TypeError: Cannot set... │ │
│ └──────────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌──────────────────────────┐ ┌───────────────────────────────┐ │
│ │ 性能趋势(LCP/FID/CLS) │ │ 新错误(今日新增) │ │
│ │ 🟢 LCP 2.5s │ │ • TypeError: Cannot read... │ │
│ │ 🟡 FID 120ms │ │ • AxiosError: Network Er... │ │
│ │ 🟢 CLS 0.08 │ │ • ReferenceError: foo i... │ │
│ │ │ │ │ │
│ └──────────────────────────┘ └───────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 实时错误流(最近 5 分钟) │ │
│ │ 14:32:15 TypeError: Cannot read property 'foo' │ │
│ │ 14:32:10 AxiosError: Request failed with 500 │ │
│ │ 14:32:05 ReferenceError: x is not defined │ │
│ │ ... │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
设计要点:
- 5 个核心指标卡片放在最上面,一眼看完
- 指标卡片底部的小数字是「同比昨日」,红涨绿跌
- 左图右表,趋势 + Top 排行
- 底部实时流,让你感知系统状态
4.2 错误列表页(Errors)
定位:浏览和管理错误 Issue,找到要处理的问题
┌─────────────────────────────────────────────────────────────────┐
│ 错误 Issues [24h ▼] [🔍 搜索错误消息] │
│ 128 个错误 · 12 个未解决 · 3 个今日新增 [状态: 全部 ▼] [级别: ▼] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌───┬─────────────────────┬──────┬───────┬───────┬──────────┐ │
│ │ ✓ │ 错误消息 │ 级别 │ 次数 │ 用户 │ 最后出现 │ │
│ ├───┼─────────────────────┼──────┼───────┼───────┼──────────┤ │
│ │ 🔴│Cannot read property│error │ 456 │ 123 │ 2 分钟前 │ │
│ │ │ 'foo' of undefined│ │ │ │ │ │
│ ├───┼─────────────────────┼──────┼───────┼───────┼──────────┤ │
│ │ 🔴│AxiosError: Request │error │ 234 │ 89 │ 5 分钟前 │ │
│ │ │ failed with 500 │ │ │ │ │ │
│ ├───┼─────────────────────┼──────┼───────┼───────┼──────────┤ │
│ │ 🟡│ReferenceError: x is│warning│ 123 │ 45 │ 12 分钟前 │ │
│ │ │ not defined │ │ │ │ │ │
│ └───┴─────────────────────┴──────┴───────┴───────┴──────────┘ │
│ │
│ ◀ 1 2 3 4 ... 12 ▶ 每页 20 条 ▼ │
│ │
└─────────────────────────────────────────────────────────────────┘
筛选器:
- 时间范围(15m / 1h / 6h / 24h / 7d / 30d / 自定义)
- 状态(全部 / 未解决 / 已解决 / 已忽略)
- 级别(全部 / fatal / error / warning / info)
- 搜索(错误消息、指纹、文件路径)
- 环境
- 版本(release)
列表交互:
- 点击行 → 进入错误详情
- 行前 checkbox → 批量操作(标记已解决、忽略)
- hover 行 → 显示快捷操作(查看、已解决、忽略)
4.3 错误详情页
定位:深入分析单个错误,定位根因
┌─────────────────────────────────────────────────────────────────┐
│ ← 返回列表 [标记已解决] [忽略] [分配给 ▼] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 🔴 TypeError: Cannot read property 'foo' of undefined │
│ Uncaught exception · active · 来自浏览器 JS │
│ │
│ 📊 概览 📝 堆栈 📋 Breadcrumbs 👥 用户 🌐 分布 ⏱️ 趋势 │
│ ───── │
│ │
│ ┌──────────────┬──────────────┬──────────────┬──────────────┐ │
│ │ 总次数 │ 影响用户 │ 首次出现 │ 最后出现 │ │
│ │ 456 │ 123 │ 3 天前 │ 2 分钟前 │ │
│ └──────────────┴──────────────┴──────────────┴──────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 发生趋势(7 天) │ │
│ │ ╱╲ │ │
│ │ ╱ ╲ ╱╲ │ │
│ │ ╱╲╱ ╲╱ ╲ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 堆栈跟踪 │ │
│ │ 📄 app.js:123 onClick │ │
│ │ 📄 utils.js:45 handleClick │ │
│ │ 📄 index.js:8 main │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 最近出现(最新 5 条) │ │
│ │ 14:32:15 user_123 Chrome 120 macOS 点击按钮时 │ │
│ │ 14:31:45 user_456 Safari 17 iOS 加载页面时 │ │
│ │ ... │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Tab 内容:
- 概览:核心数据 + 趋势图 + 最近出现
- 堆栈:完整堆栈跟踪,可折叠,点击跳源码(如果配置了 sourcemap)
- Breadcrumbs:用户操作路径,时间线展示
- 用户:受影响的用户列表
- 分布:浏览器、OS、设备、地区分布
- 趋势:更长时间的趋势图
4.4 性能分析页
定位:看页面性能好不好,哪里慢
┌─────────────────────────────────────────────────────────────────┐
│ 性能分析 [24h ▼] [页面: 全部 ▼] │
│ Web Vitals 指标 [浏览器: 全部 ▼] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌───────────┐ │
│ │ LCP │ │ FID │ │ CLS │ │ FCP │ │
│ │ 3.2s 🔴 │ │ 120ms 🟡 │ │ 0.15 🟢 │ │ 1.8s 🟡 │ │
│ │ P95: 4.5s │ │ P95: 200ms │ │ P95: 0.25 │ │ P95: 2.5s│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └───────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 性能趋势(P50 / P75 / P95 / P99) │ │
│ │ ╭────────────────────────────────────────────────────╮ │ │
│ │ │ ▲ P99 ── P95 ─ ─ P75 ┄ ┄ P50 │ │ │
│ │ │ │╲ │ │ │
│ │ │ │ ╲──────╮ │ │ │
│ │ │ │ ╲╱╲ │ │ │
│ │ │ │ │ │ │
│ │ │ ╰───────────────────────────────────────────────╯ │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 页面性能排行 [按 LCP 排序 ▼] │ │
│ ├─────────────────────┬──────┬──────┬──────┬──────┬───────┤ │
│ │ 页面 │ LCP │ FID │ CLS │ 样本 │ 评级 │ │
│ ├─────────────────────┼──────┼──────┼──────┼──────┼───────┤ │
│ │ /home │ 2.8s │ 80ms │ 0.10 │ 1.2k │ 🟢 良 │ │
│ │ /product/:id │ 4.2s │ 150ms│ 0.20 │ 800 │ 🔴 差 │ │
│ │ /checkout │ 3.5s │ 120ms│ 0.15 │ 500 │ 🟡 中 │ │
│ │ ... │ │ │ │ │ │ │
│ └─────────────────────┴──────┴──────┴──────┴──────┴───────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
4.5 告警中心
定位:配置告警规则,查看告警历史
┌─────────────────────────────────────────────────────────────────┐
│ 告警中心 │
│ ┌─────────┐ │
│ │ 告警规则 │ 告警历史 │
│ └─────────┘ │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [+ 新建告警规则] │
│ │
│ ┌───┬─────────────────────┬──────────┬───────┬────────┬─────┐ │
│ │ ✓ │ 规则名称 │ 类型 │ 级别 │ 状态 │ 操作 │ │
│ ├───┼─────────────────────┼──────────┼───────┼────────┼─────┤ │
│ │ 🔔│ 错误数量突增 │ 突增告警 │ 严重 │ ✅ 启用 │ ... │ │
│ ├───┼─────────────────────┼──────────┼───────┼────────┼─────┤ │
│ │ 🔔│ 新错误出现 │ 新错误 │ 警告 │ ✅ 启用 │ ... │ │
│ ├───┼─────────────────────┼──────────┼───────┼────────┼─────┤ │
│ │ 🔔│ LCP 超过 4s │ 阈值告警 │ 警告 │ ✅ 启用 │ ... │ │
│ └───┴─────────────────────┴──────────┴───────┴────────┴─────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
五、组件设计
5.1 指标卡片
┌─────────────────┐
│ 错误总数 │ ← 标题(小字、灰色)
│ 128 │ ← 数值(大字、粗体)
│ ↑ 15% vs 昨日 │ ← 趋势(红涨绿跌)
│ ╱╲ │ ← 迷你趋势图(可选)
│ ╱ ╲ │
└─────────────────┘
变体:
- 标准:数字 + 趋势
- 带评级:数字 + 颜色评级(性能指标用)
- 极简:只有数字
5.2 状态标签
| 状态 | 颜色 | 示例 |
|---|---|---|
| Active(未解决) | 红底白字 | active |
| Resolved(已解决) | 绿底白字 | resolved |
| Ignored(已忽略) | 灰底灰字 | ignored |
| Firing(告警中) | 红底白字 | FIRING |
| Resolved(已恢复) | 绿底白字 | RESOLVED |
5.3 错误级别标记
| 级别 | 颜色 |
|---|---|
| Fatal | 🔴 深红 |
| Error | 🔴 红 |
| Warning | 🟡 黄 |
| Info | 🔵 蓝 |
| Debug | ⚪ 灰 |
5.4 性能评级
| 评级 | 颜色 | LCP | FID | CLS |
|---|---|---|---|---|
| Good 🟢 | 绿 | < 2.5s | < 100ms | < 0.1 |
| Needs Improvement 🟡 | 黄 | 2.5-4s | 100-300ms | 0.1-0.25 |
| Poor 🔴 | 红 | > 4s | > 300ms | > 0.25 |
六、图表设计
6.1 图表库选型
| 库 | 体积 | 功能 | 适合场景 |
|---|---|---|---|
| Chart.js | ~60KB gzip | 基础图表够用 | 轻量、简单 |
| ECharts | ~150KB gzip | 功能强大 | 复杂图表、交互多 |
| uPlot | ~15KB gzip | 时序图表 | 极致轻量、性能好 |
推荐方案:
- 默认用 Chart.js(够用、轻量、生态好)
- 性能监控页面用 ECharts(需要更复杂的交互)
- 可按需加载,首屏只加载必要的
6.2 图表类型
| 图表 | 用途 | 页面 |
|---|---|---|
| 折线图 | 错误趋势、性能趋势 | 概览、错误、性能 |
| 柱状图 | Top N 排行、分布 | 错误、性能 |
| 饼图 / 环形图 | 占比、分布 | 概览、错误 |
| 面积图 | 堆叠趋势 | 性能 |
| 热力图 | 时间段分布 | 错误 |
6.3 与 Grafana 的关系
管理后台解决的问题:
- 错误 Issue 管理(状态、分配、标记)
- 项目配置和管理
- 告警规则配置
- 更友好的错误详情展示
Grafana 解决的问题:
- 灵活的自定义仪表盘
- 复杂的数据探索
- 多种数据源联合查询
- 告警(可复用 Grafana Alerting)
分工原则:
- 常用功能做进管理后台(开箱即用)
- 高级分析用 Grafana(灵活强大)
- 管理后台提供一键跳转到 Grafana 的链接
七、前端架构
7.1 目录结构
frontend/ # 前端工程(独立目录)
├── public/
│ └── favicon.ico
├── src/
│ ├── assets/ # 静态资源
│ │ ├── images/
│ │ └── icons/
│ ├── components/ # 通用组件
│ │ ├── layout/ # 布局组件
│ │ │ ├── MainLayout.tsx # 主布局(侧边栏+顶栏+内容)
│ │ │ ├── Sidebar.tsx # 侧边栏
│ │ │ ├── Header.tsx # 顶部栏
│ │ │ └── PageHeader.tsx # 页面头
│ │ ├── chart/ # 图表组件
│ │ │ ├── LineChart.tsx # 折线图
│ │ │ ├── BarChart.tsx # 柱状图
│ │ │ └── PieChart.tsx # 饼图
│ │ ├── metrics/ # 指标组件
│ │ │ └── MetricCard.tsx # 指标卡片
│ │ └── common/ # 其他通用组件
│ │ ├── StatusTag.tsx # 状态标签
│ │ └── CopyButton.tsx # 复制按钮
│ ├── pages/ # 页面
│ │ ├── overview/ # 概览页
│ │ │ └── index.tsx
│ │ ├── errors/ # 错误管理
│ │ │ ├── List.tsx # 错误列表
│ │ │ └── Detail.tsx # 错误详情
│ │ ├── performance/ # 性能分析
│ │ │ └── index.tsx
│ │ ├── network/ # 网络分析
│ │ │ └── index.tsx
│ │ ├── alerts/ # 告警中心
│ │ │ ├── Rules.tsx # 告警规则
│ │ │ └── History.tsx # 告警历史
│ │ ├── logs/ # 日志查询
│ │ │ └── index.tsx
│ │ ├── settings/ # 项目设置
│ │ │ └── index.tsx
│ │ ├── projects/ # 项目管理
│ │ │ └── List.tsx
│ │ └── integration/ # 接入指南
│ │ └── index.tsx
│ ├── store/ # 状态管理 (Zustand)
│ │ ├── index.ts # 导出
│ │ ├── useAppStore.ts # 全局状态(主题、侧边栏等)
│ │ └── useProjectStore.ts # 当前项目状态
│ ├── services/ # API 服务
│ │ ├── request.ts # Axios 封装
│ │ ├── project.ts # 项目相关 API
│ │ ├── error.ts # 错误相关 API
│ │ ├── performance.ts # 性能相关 API
│ │ └── alert.ts # 告警相关 API
│ ├── hooks/ # 自定义 Hooks
│ │ ├── useProject.ts # 当前项目 hook
│ │ ├── useTimeRange.ts # 时间范围 hook
│ │ └── useChartTheme.ts # 图表主题 hook
│ ├── router/ # 路由配置
│ │ ├── index.tsx # 路由入口
│ │ └── routes.ts # 路由表
│ ├── utils/ # 工具函数
│ │ ├── format.ts # 格式化(时间、数字等)
│ │ ├── date.ts # 日期工具
│ │ └── storage.ts # 本地存储
│ ├── types/ # TypeScript 类型定义
│ │ ├── api.ts # API 类型
│ │ ├── error.ts # 错误相关类型
│ │ ├── performance.ts # 性能相关类型
│ │ └── common.ts # 通用类型
│ ├── styles/ # 全局样式
│ │ ├── global.less
│ │ └── variables.less
│ ├── App.tsx # 根组件
│ └── main.tsx # 入口文件
├── .eslintrc.js # ESLint 配置
├── .prettierrc # Prettier 配置
├── tsconfig.json # TypeScript 配置
├── vite.config.ts # Vite 配置
└── package.json
7.2 路由设计
使用 React Router v6,嵌套路由 + 懒加载:
// router/routes.ts
const routes = [
{
path: '/',
element: <MainLayout />,
children: [
{ index: true, element: <Navigate to="/overview" replace /> },
{ path: 'overview', lazy: () => import('@/pages/overview') },
{
path: 'errors',
children: [
{ index: true, lazy: () => import('@/pages/errors/List') },
{ path: ':id', lazy: () => import('@/pages/errors/Detail') },
],
},
{ path: 'performance', lazy: () => import('@/pages/performance') },
{ path: 'network', lazy: () => import('@/pages/network') },
{
path: 'alerts',
children: [
{ index: true, element: <Navigate to="rules" replace /> },
{ path: 'rules', lazy: () => import('@/pages/alerts/Rules') },
{ path: 'history', lazy: () => import('@/pages/alerts/History') },
],
},
{ path: 'logs', lazy: () => import('@/pages/logs') },
{ path: 'settings', lazy: () => import('@/pages/settings') },
{ path: 'integration', lazy: () => import('@/pages/integration') },
],
},
{ path: '/projects', element: <ProjectList /> },
{ path: '*', element: <NotFound /> },
];
7.3 状态管理(Zustand)
为什么用 Zustand 而不是 Redux?
- 比 Redux 简单太多,没有 reducer、action、dispatch 那些概念
- 体积小(~1KB),性能好
- TypeScript 支持好
- 支持 middleware(persist、devtools 等)
// store/useAppStore.ts
import { create } from 'zustand';
interface AppState {
theme: 'dark' | 'light';
sidebarCollapsed: boolean;
currentProject: Project | null;
toggleTheme: () => void;
toggleSidebar: () => void;
setCurrentProject: (project: Project) => void;
}
export const useAppStore = create<AppState>((set) => ({
theme: 'dark',
sidebarCollapsed: false,
currentProject: null,
toggleTheme: () => set((s) => ({ theme: s.theme === 'dark' ? 'light' : 'dark' })),
toggleSidebar: () => set((s) => ({ sidebarCollapsed: !s.sidebarCollapsed })),
setCurrentProject: (project) => set({ currentProject: project }),
}));
7.4 数据请求(TanStack Query)
为什么用 TanStack Query?
- 自动缓存,相同请求不会重复发
- 后台自动刷新
- 分页、无限滚动都有封装
- 乐观更新、重试策略
- 和 Zustand 互补,不用把 API 数据放全局 store
// hooks/useErrors.ts
import { useQuery } from '@tanstack/react-query';
import { getErrorList } from '@/services/error';
export function useErrorList(params: ErrorListParams) {
return useQuery({
queryKey: ['errors', params],
queryFn: () => getErrorList(params),
keepPreviousData: true,
staleTime: 30_000, // 30秒内认为是新鲜的
});
}
7.5 请求封装(Axios)
// services/request.ts
import axios from 'axios';
import { message } from 'antd';
const request = axios.create({
baseURL: '/api',
timeout: 15000,
});
// 请求拦截器:加 token
request.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
// 响应拦截器:统一处理错误
request.interceptors.response.use(
(res) => res.data,
(err) => {
const status = err.response?.status;
const message = err.response?.data?.message || err.message;
if (status === 401) {
// 登录过期,跳登录页
} else {
message.error(message);
}
return Promise.reject(err);
}
);
export default request;
7.6 主题配置(Ant Design 5 深色主题)
Ant Design 5 用 CSS-in-JS,通过 ConfigProvider 配置主题:
// App.tsx
import { ConfigProvider, theme as antdTheme } from 'antd';
import { useAppStore } from '@/store';
function App() {
const { theme } = useAppStore();
return (
<ConfigProvider
theme={{
algorithm: theme === 'dark'
? antdTheme.darkAlgorithm
: antdTheme.defaultAlgorithm,
token: {
colorPrimary: '#0090f9',
borderRadius: 6,
},
}}
>
<Router />
</ConfigProvider>
);
}
自定义暗色主题色板(贴合 GitHub Dark 风格):
{
colorBgLayout: '#0d1117', // 页面背景
colorBgContainer: '#161b22', // 卡片背景
colorBgElevated: '#21262d', // 悬浮背景
colorBorder: '#30363d', // 边框
colorText: '#e6edf3', // 主文字
colorTextSecondary: '#8b949e',// 次文字
colorTextTertiary: '#6e7681', // 弱文字
}
7.7 图表封装
基于 ECharts 封装通用图表组件,自动适配主题和容器大小:
// components/chart/BaseChart.tsx
import { useEffect, useRef } from 'react';
import * as echarts from 'echarts';
import { useAppStore } from '@/store';
interface BaseChartProps {
option: echarts.EChartsOption;
height?: number | string;
className?: string;
}
export function BaseChart({ option, height = 300, className }: BaseChartProps) {
const chartRef = useRef<HTMLDivElement>(null);
const chartInstance = useRef<echarts.ECharts | null>(null);
const { theme } = useAppStore();
useEffect(() => {
if (!chartRef.current) return;
chartInstance.current = echarts.init(
chartRef.current,
theme === 'dark' ? 'dark' : null
);
const resizeObserver = new ResizeObserver(() => {
chartInstance.current?.resize();
});
resizeObserver.observe(chartRef.current);
return () => {
resizeObserver.disconnect();
chartInstance.current?.dispose();
};
}, [theme]);
useEffect(() => {
chartInstance.current?.setOption(option, true);
}, [option]);
return <div ref={chartRef} style={{ height }} className={className} />;
}
7.8 构建与部署
开发环境:
pnpm dev # 启动开发服务器
pnpm build # 生产构建
pnpm preview # 预览构建结果
pnpm lint # ESLint 检查
pnpm type-check # TypeScript 类型检查
部署方案:
- 构建产物:
dist/目录 - Nginx 直接托管静态文件
- API 请求通过 Nginx 反向代理到后端
- 和现有
public/manage/共存,新前端走/manage/路径
location /manage/ {
try_files $uri $uri/ /manage/index.html;
root /path/to/frontend/dist;
}
八、交互设计原则
8.1 快速导航
- 全局搜索:
⌘K唤起,可搜项目、错误、页面 - 面包屑:永远知道自己在哪
- 相关跳转:错误详情里可跳转到对应页面的性能分析
8.2 数据加载
- 骨架屏:数据加载中显示骨架,不跳
- 增量加载:列表滚动加载
- 实时刷新:可开/关,默认 30 秒自动刷新
8.3 操作反馈
- 重要操作(删除、标记已解决)有确认弹窗
- 成功操作顶部弹 toast,3 秒自动消失
- 操作失败显示错误原因,可重试
九、API 设计
9.1 统计 API
# 概览数据
GET /api/projects/{id}/overview?time_range=24h
# 错误趋势
GET /api/projects/{id}/errors/trend?time_range=24h&interval=1h
# 错误列表
GET /api/projects/{id}/errors?page=1&page_size=20&level=error&status=active
# 错误详情
GET /api/projects/{id}/errors/{fingerprint}
# 性能指标
GET /api/projects/{id}/performance/metrics?time_range=24h&metric=lcp
# 告警规则
GET /api/projects/{id}/alerts/rules
POST /api/projects/{id}/alerts/rules
PUT /api/projects/{id}/alerts/rules/{rule_id}
DELETE /api/projects/{id}/alerts/rules/{rule_id}
# 告警历史
GET /api/projects/{id}/alerts/history?page=1&page_size=20
十、演进路线
10.1 当前状态
现有的 index.html 是项目列表页,只有最基础的 CRUD 功能。
10.2 版本规划
v1.1(下一个版本):
- 改造成侧边栏 + 内容区的布局
- 新增概览页(核心指标 + 错误趋势)
- 新增错误列表页(从聚合表读)
- 项目选择器移到顶部
v1.2:
- 错误详情页
- 性能分析页
- 告警规则管理
v2.0:
- 完整的错误管理工作流
- 性能深入分析(瀑布图、资源时序)
- 用户会话追踪