docs: P0 implementation plan - alarm center, face gallery, video monitor, dashboard

This commit is contained in:
tian 2026-05-07 10:12:43 +08:00
parent 8c54a82605
commit 002b082faa

289
docs/P0实施计划.md Normal file
View File

@ -0,0 +1,289 @@
# P0 功能实施计划
> 计划日期2026-05-06
> 基于:产品化评估与规划.md 中的 P0 优先级
---
## 总览
| 功能 | 依赖链 | 工作量估计 |
|------|--------|-----------|
| 告警中心 | media-server → agent → 后端 | 最大 |
| 人脸库管理 | agent → 后端 | 中 |
| 视频监控 | agent → 后端 | 中 |
| Dashboard 改造 | 后端(依赖以上三项) | 小 |
---
## 一、告警中心(最大的缺口)
### 1.1 当前问题
media-server 的 alarm 节点触发告警后直接发送给第三方HTTP 回调、MinIO 等),**不在本地保存告警记录**。agent 无法查询历史告警,后端自然也无法展示。
### 1.2 架构设计
```
media-server alarm 节点触发
├── 截图/视频片段上传 MinIO已有
├── HTTP 回调通知第三方(已有)
└── 写入本地告警日志(新增)──→ agent 查询 ──→ 后端收集展示
```
### 1.3 告警记录格式
```json
{
"id": "alarm_20260506_143021_a1b2c3",
"timestamp": "2026-05-06T14:30:21+08:00",
"device_id": "d12a4719c91641df",
"channel": "cam1",
"rule_name": "intrusion_zone_a",
"rule_type": "intrusion",
"object_label": "person",
"confidence": 0.87,
"snapshot_url": "http://minio:9000/alarms/xxx.jpg",
"clip_url": "http://minio:9000/clips/xxx.mp4",
"duration_ms": 3500
}
```
### 1.4 任务分解
#### Task A1media-server 增加本地告警存储C++
**文件**`plugins/alarm/alarm_node.cpp`
在 alarm 节点触发告警动作时,追加写入本地 SQLite 数据库:
```
表结构:
CREATE TABLE alarm_records (
id TEXT PRIMARY KEY,
timestamp TEXT NOT NULL,
channel TEXT NOT NULL,
rule_name TEXT NOT NULL,
rule_type TEXT NOT NULL,
object_label TEXT,
confidence REAL,
snapshot_url TEXT,
clip_url TEXT,
duration_ms INTEGER,
created_at TEXT NOT NULL
);
```
位置:`${modelsDir}/../resources/alarms/alarm_records.db`
#### Task A2agent 增加告警查询端点Go
**文件**`agent/internal/httpapi/alarms.go`(新建)
```
GET /v1/alarms/recent?limit=50&since=2026-05-06T00:00:00
```
返回最近 N 条告警记录。可选时间范围过滤。
#### Task A3后端定时收集设备告警Go
**文件**`internal/service/alarm_collector.go`(新建)
- RegistryService 增加 goroutine每 10 秒遍历在线设备
- 对每个设备调用 `agent.Do("GET", dev.IP, dev.AgentPort, "/v1/alarms/recent?limit=100", nil)`
- 新告警写入后端 SQLite`alarm_records` 表)
- 前端 SSE 推送新告警
**数据库**`internal/storage/migrate.go` 新增表
```sql
CREATE TABLE IF NOT EXISTS alarm_records (
id TEXT PRIMARY KEY,
device_id TEXT NOT NULL,
channel TEXT NOT NULL,
timestamp TEXT NOT NULL,
rule_name TEXT NOT NULL,
rule_type TEXT NOT NULL,
object_label TEXT,
confidence REAL,
snapshot_url TEXT,
clip_url TEXT,
duration_ms INTEGER,
collected_at TEXT NOT NULL
);
```
#### Task A4告警中心页面Go + HTML
**路由**`GET /ui/alarms`
**布局**
- 上半部分:告警筛选(设备/通道/规则类型/时间范围)
- 下半部分:告警列表(时间、设备、通道、规则、对象标签、截图缩略图、视频链接)
- 点击进入告警详情(大图、视频片段播放)
#### Task A5Dashboard 告警信息流HTML + JS
在 Dashboard 顶部增加一个告警信息流卡片SSE 实时推送最近 5 条告警。
---
## 二、人脸库管理
### 2.1 当前问题
只能整文件上传/替换 `.db`,无法增删改单个人物。
### 2.2 架构设计
```
后端人脸库页面 ──CRUD──▶ agent /v1/face-gallery/persons/* ──▶ media-server face_gallery.db
```
### 2.3 任务分解
#### Task B1agent 增加人脸库 CRUD APIGo
**文件**`agent/internal/httpapi/face_gallery.go`(修改)
新增端点:
- `GET /v1/face-gallery/persons` — 返回人物列表 {id, name, photo_count, created_at}
- `POST /v1/face-gallery/persons` — 新增人物 {name, photo_bytes}agent 调用 media-server 接口提取 embedding 并写入 DB
- `DELETE /v1/face-gallery/persons/{id}` — 删除人物及其 embeddings
- `PUT /v1/face-gallery/persons/{id}/name` — 修改人物姓名
- `POST /v1/face-gallery/persons/{id}/photo` — 追加人脸照片,提取 embedding
#### Task B2后端人脸库管理页面Go + HTML
**路由**`GET /ui/face-gallery`
**布局**
- 人员列表(姓名、照片缩略图、注册时间、操作按钮)
- 搜索框(按姓名搜索)
- 新增按钮 → 弹出表单(姓名 + 上传照片)
- 编辑/删除确认
---
## 三、视频监控
### 3.1 当前问题
后台看不到摄像头画面。只能通过 `http://设备IP:9000/hls_player.html` 在设备上查看。
### 3.2 架构设计
```
后端视频监控页 ──iframe──▶ agent 返回 HLS 播放页面 URL
└──img──▶ agent /v1/preview/snapshot?channel=X 返回 JPEG
```
### 3.3 任务分解
#### Task C1agent 增加预览端点Go
**文件**`agent/internal/httpapi/preview.go`(新建)
- `GET /v1/preview/channels` — 返回各通道信息 {name, hls_url, rtsp_url, resolution, fps}
- `GET /v1/preview/snapshot/:channel` — 从 media-server 请求当前帧,返回 JPEG
HLS URL 格式:代理转发到 media-server 的 `/hls/{channel}/index.m3u8`
#### Task C2后端视频监控页面Go + HTML
**路由**`GET /ui/monitor`
**布局**
- 左侧:设备通道列表(可多选)
- 右侧多路画面网格4/9/16 宫格)
- 每个画面HLS 播放器 iframe + 通道名称标签
- 单击画面可全屏
---
## 四、Dashboard 改造
### 4.1 当前问题
只有静态统计(设备数、任务数),缺乏实时信息。
### 4.2 目标布局
```
┌─────────────────────────────────────┐
│ 实时告警5条滚动 │ ← 告警中心对接
├──────────┬──────────┬───────────────┤
│ 设备状态 │ NPU/CPU │ 今日告警统计 │ ← agent metrics
│ 在线 3/3 │ ████░░░░ │ 告警: 12 │
├──────────┴──────────┴───────────────┤
│ 关键通道预览1-4路 snapshot │ ← 视频监控对接
├─────────────────────────────────────┤
│ 最近任务 │ ← 已有
└─────────────────────────────────────┘
```
### 4.3 任务分解
#### Task D1Dashboard 实时数据 APIGo
**文件**`internal/web/ui.go`(修改 `pageDashboard`
```go
func (u *UI) pageDashboard(w http.ResponseWriter, r *http.Request) {
u.ensureDevicesLoaded()
data := ...现有逻辑...
// 新增:最近告警
data.RecentAlarms = alarmService.GetRecent(5)
// 新增:设备 metrics聚合
data.DeviceMetrics = collectDeviceMetrics(u.agent, u.registry)
u.render(w, r, "dashboard", data)
}
```
#### Task D2Dashboard 模板改造HTML
**文件**`internal/web/ui/templates/dashboard.html`
- 告警信息流SSE 实时更新)
- 设备状态卡片在线数、CPU、内存
- 快照预览(定时刷新 img src
- 最近任务(已有,保留)
---
## 五、实施顺序
```
第一阶段(打通告警链路):
Task A1media-server→ Task A2agent→ Task A3后端收集→ Task A4告警页面
第二阶段(人脸库 + 视频):
Task B1 + C1agent→ Task B2 + C2后端页面
第三阶段Dashboard整合
Task A5 + D1 + D2Dashboard 改造)
```
---
## 六、涉及文件清单
| 项目 | 文件 | 操作 |
|------|------|------|
| media-server | `plugins/alarm/alarm_node.cpp` | 修改:追加本地告警存储 |
| agent | `internal/httpapi/alarms.go` | 新建:告警查询端点 |
| agent | `internal/httpapi/face_gallery.go` | 修改:人脸库 CRUD |
| agent | `internal/httpapi/preview.go` | 新建:视频预览端点 |
| agent | `internal/httpapi/server.go` | 修改:注册新路由 |
| 后端 | `internal/service/alarm_collector.go` | 新建:告警收集服务 |
| 后端 | `internal/storage/migrate.go` | 修改alarm_records 表 |
| 后端 | `internal/web/ui/templates/alarms.html` | 新建:告警中心页面 |
| 后端 | `internal/web/ui/templates/face_gallery.html` | 新建:人脸库管理页面 |
| 后端 | `internal/web/ui/templates/monitor.html` | 新建:视频监控页面 |
| 后端 | `internal/web/ui/templates/dashboard.html` | 修改:实时化改造 |
| 后端 | `internal/web/ui.go` | 修改:新页面 handler + 路由 |
| 后端 | `cmd/managerd/main.go` | 修改:注入新服务 |