refactor: 前端架构重构 — hook拆分、组件拆分、类型筛选器动态化、Meta API
- 后端新增 GET /api/meta 端点(checkerRegistry.supportedTypes)及 MetaResponse 类型 - 前端 hook 拆分为 use-queries.ts(全局查询+useMeta)和 use-target-detail.ts(Drawer状态) - TargetDetailDrawer 拆分为 OverviewTab + HistoryTab + history-table-columns + stats.ts - 类型筛选器由 meta API 动态驱动,删除 target-type-display 静态映射 - 列定义改为工厂函数 createTargetTableColumns(checkerTypes),TargetGroup 新增 columns prop - 修复 StatusDonut key、StatusBar maxSlots prop、TrendChart 移除 loading prop - 补充 utils/time、utils/stats、动态列工厂测试,删除旧 mapping 测试 - 同步 delta specs 到主 specs,归档 frontend-architecture-refactor change
This commit is contained in:
@@ -67,15 +67,17 @@ src/
|
||||
styles.css 全局样式与自定义 CSS 变量
|
||||
components/ UI 组件(见下方组件清单)
|
||||
constants/ 常量与纯函数
|
||||
target-type-display.ts 类型名称映射
|
||||
target-table-columns.tsx 表格列定义
|
||||
history-table-columns.tsx 历史记录表格列定义
|
||||
target-table-columns.tsx 目标表格列定义工厂
|
||||
target-table-filters.ts 表格筛选器
|
||||
target-table-sorters.ts 表格排序器
|
||||
color-threshold.ts 可用率颜色阈值函数
|
||||
hooks/ TanStack Query 数据层
|
||||
useTargetDetail.ts 集成轮询/条件查询的组合 hook
|
||||
use-queries.ts 全局面板查询 hook(summary/targets/meta)
|
||||
use-target-detail.ts 目标详情 Drawer 状态与条件查询 hook
|
||||
utils/ 前端工具函数
|
||||
time.ts 时间处理(subtractHours)
|
||||
stats.ts 趋势统计计算(computeTrendStats)
|
||||
scripts/ 开发、构建、schema 生成和 smoke test 脚本
|
||||
tests/ Bun test 测试(结构镜像 src 目录)
|
||||
openspec/ OpenSpec 变更与规格文档
|
||||
@@ -358,14 +360,11 @@ TcpChecker implements Checker
|
||||
| `engine.ts` | 按 `target.type` 从 registry 取对应 checker 执行 `execute()` |
|
||||
| `store.ts` | 按 `target.type` 从 registry 取对应 checker 执行 `serialize()` |
|
||||
|
||||
注意:自动适配指上述中间层不需要新增 `switch/case` 或类型分支;开发者仍需按后续步骤更新前端展示常量、配置示例、文档和测试。
|
||||
注意:自动适配指上述中间层不需要新增 `switch/case` 或类型分支;开发者仍需按后续步骤更新配置示例、文档和测试。
|
||||
|
||||
#### 1.7.7 步骤六:更新前端展示
|
||||
#### 1.7.7 步骤六:确认前端类型展示
|
||||
|
||||
| 文件 | 修改内容 |
|
||||
| ------------------------------------------- | ------------------------------------------------------------ |
|
||||
| `src/web/constants/target-type-display.ts` | 在 `TARGET_TYPE_DISPLAY` 中添加 `"tcp": "TCP"` |
|
||||
| `src/web/constants/target-table-filters.ts` | 在 `typeFilter.list` 中添加 `{ label: "TCP", value: "tcp" }` |
|
||||
前端通过 `/api/meta` 获取 `checkerRegistry.supportedTypes` 并动态生成类型筛选器,类型列和详情标题直接显示 `target.type` 原始文本。新增 checker 注册后无需更新前端类型映射或筛选常量。
|
||||
|
||||
#### 1.7.8 步骤七:编写测试
|
||||
|
||||
@@ -400,8 +399,6 @@ TcpChecker implements Checker
|
||||
□ src/server/checker/runner/tcp/expect.ts — 专用断言(如需要)
|
||||
□ src/server/checker/runner/tcp/index.ts — 模块入口(re-export)
|
||||
□ src/server/checker/runner/index.ts — 注册(一行导入 + 一个数组元素)
|
||||
□ src/web/constants/target-type-display.ts — 前端类型标签
|
||||
□ src/web/constants/target-table-filters.ts — 前端类型筛选
|
||||
□ tests/ — 契约 + 校验 + resolve + execute + 注册 测试
|
||||
□ probes.example.yaml — 配置示例
|
||||
□ bun run schema + bun run schema:check — Schema 导出同步
|
||||
@@ -544,26 +541,29 @@ main.tsx
|
||||
│ │ └── useSummary() ─── GET /api/summary(8s 轮询)
|
||||
│ └── TargetBoard(目标列表)
|
||||
│ ├── useTargets() ─── GET /api/targets(8s 轮询)
|
||||
│ ├── useMeta() ────── GET /api/meta(应用生命周期内缓存)
|
||||
│ └── TargetGroup[](按 group 字段分组)
|
||||
│ └── PrimaryTable ← TARGET_TABLE_COLUMNS(列定义:排序/筛选/渲染)
|
||||
│ └── PrimaryTable ← createTargetTableColumns(checkerTypes)
|
||||
│ └── TargetDetailDrawer(目标详情抽屉)
|
||||
│ └── useTargetDetail() ── 按需发起 trend + history 查询
|
||||
│ ├── Tab: 概览 → Statistic + TrendChart + StatusDonut + Descriptions
|
||||
│ └── Tab: 记录 → PrimaryTable(分页历史记录)
|
||||
│ ├── OverviewTab → Statistic + TrendChart + StatusDonut + Descriptions
|
||||
│ └── HistoryTab → PrimaryTable(分页历史记录)
|
||||
└── ReactQueryDevtools(开发工具,仅开发环境)
|
||||
```
|
||||
|
||||
**数据层架构**:
|
||||
|
||||
```
|
||||
hooks/useTargetDetail.ts(唯一的数据层入口)
|
||||
├── queryKeys(结构化 query key,确保缓存粒度精确)
|
||||
hooks/use-queries.ts(全局面板级查询)
|
||||
├── queryKeys(summary/targets/meta 结构化 query key)
|
||||
├── useSummary() → /api/summary(8s 自动轮询)
|
||||
├── useTargets() → /api/targets(8s 自动轮询)
|
||||
└── useTargetDetail()(组合 hook,管理 Drawer 全部状态)
|
||||
├── 内部复用 useTargets() 的缓存来查找 selectedTarget
|
||||
├── useQuery(/api/targets/:id/trend)(条件查询:enabled 仅当 Drawer 打开且时间范围有效)
|
||||
└── useQuery(/api/targets/:id/history)(条件查询:含分页)
|
||||
└── useMeta() → /api/meta(staleTime: Infinity)
|
||||
|
||||
hooks/use-target-detail.ts(Drawer 状态与详情级条件查询)
|
||||
├── 内部复用 useTargets() 的缓存来查找 selectedTarget
|
||||
├── useQuery(/api/targets/:id/trend)(条件查询:enabled 仅当 Drawer 打开且时间范围有效)
|
||||
└── useQuery(/api/targets/:id/history)(条件查询:含分页)
|
||||
```
|
||||
|
||||
### 2.3 TanStack Query 数据层
|
||||
@@ -574,6 +574,7 @@ hooks/useTargetDetail.ts(唯一的数据层入口)
|
||||
const queryKeys = {
|
||||
summary: () => ["summary"] as const,
|
||||
targets: () => ["targets"] as const,
|
||||
meta: () => ["meta"] as const,
|
||||
trend: (targetId: number, from: string, to: string) => ["trend", targetId, from, to] as const,
|
||||
history: (targetId: number, from: string, to: string, page: number) => ["history", targetId, from, to, page] as const,
|
||||
};
|
||||
@@ -668,7 +669,9 @@ export function TargetGroup({ name, targets, onTargetClick }: TargetGroupProps)
|
||||
| `SummaryCards` | `components/SummaryCards.tsx` | 总览统计卡片(全部/正常/异常) |
|
||||
| `TargetBoard` | `components/TargetBoard.tsx` | 按分组渲染目标表格列表 |
|
||||
| `TargetGroup` | `components/TargetGroup.tsx` | 单个分组标题 + PrimaryTable |
|
||||
| `TargetDetailDrawer` | `components/TargetDetailDrawer.tsx` | 目标详情抽屉(概览/记录 Tab) |
|
||||
| `TargetDetailDrawer` | `components/TargetDetailDrawer.tsx` | 目标详情抽屉壳、时间选择和 Tab 切换 |
|
||||
| `OverviewTab` | `components/OverviewTab.tsx` | 目标详情概览(统计/趋势/状态分布/信息) |
|
||||
| `HistoryTab` | `components/HistoryTab.tsx` | 目标历史记录表格和分页 |
|
||||
| `TrendChart` | `components/TrendChart.tsx` | Recharts 双轴折线图(耗时/可用率) |
|
||||
| `StatusDonut` | `components/StatusDonut.tsx` | Recharts 环状图(UP/DOWN 分布) |
|
||||
| `StatusDot` | `components/StatusDot.tsx` | 圆形状态指示点(绿/红) |
|
||||
@@ -682,7 +685,7 @@ export function TargetGroup({ name, targets, onTargetClick }: TargetGroupProps)
|
||||
1. **确认数据需求**:是已有 API 数据还是需要新端点?
|
||||
- 如有新端点,先在 `src/server/routes/` 添加,参考 [1.3 新增路由步骤](#13-api-路由开发)
|
||||
- 如有新字段,更新 `src/shared/api.ts` 类型定义
|
||||
2. **实现 hooks**:在 `src/web/hooks/useTargetDetail.ts` 中新增 `useQuery`(写好 `queryKey` 和 `enabled` 条件)
|
||||
2. **实现 hooks**:全局查询放在 `src/web/hooks/use-queries.ts`;目标详情条件查询放在 `src/web/hooks/use-target-detail.ts`(写好 `queryKey` 和 `enabled` 条件)
|
||||
3. **编写组件**:在 `src/web/components/` 创建组件文件
|
||||
- 在 `TargetDetailDrawer.tsx` 中新增 `<Tabs.TabPanel>` 引用
|
||||
4. **编写常量**:如有列定义/排序器/筛选器,放在 `src/web/constants/`
|
||||
|
||||
Reference in New Issue
Block a user