3588AdminBackend/docs/P0实施计划.md

290 lines
8.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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` | 修改:注入新服务 |