Files
SecMPS/gb28181_web-main/desktop_2d_plan_todo.md

128 lines
9.0 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.
# `/web/desktop` 2D 平面图 — 开发计划与现状(替代旧版开发文档)
> 本文档替代仓库内此前的 2D 开发/说明类文档,作为**唯一**跟进源。实现以当前代码为准(`FloorPlanState` v3、世界坐标 + 网格吸附、墙线/房间/Konva 等)。
## 1. 产品目标
`/desktop` 提供**数据流拓扑**与 **2D 平面视图**两种模式,2D 用于:
- 快速理解摄像头覆盖区域(扇区)与墙线/房间示意
- 绑定真实通道、悬停查看最近 AI 事件
- 从平面图**跳转录像回放**(与产品决策一致)
- 本地持久化布局(`localStorage`,第一版不接后端平面图存储)
## 2. 当前实现概要(与旧 MVP 文档的差异)
| 原 MVP 设想 | 当前实现 |
|-------------|----------|
| 纯四边形网格 row/col | 世界坐标 `(x,y)` + 网格吸附,并支持墙线、矩形房间、预设轮廓 |
| 简单编辑 | 多选、框选、编组、撤销栈、复制粘贴、对齐辅助线等 |
| hover 按需拉事件 | 已实现;事件缓存见 `floor_plan.events.ts` |
## 3. 数据模型(摘录)
`app/pages/desktop/floor_plan.types.ts``FloorPlanState`(含 `walls``cameras``view`)、`CameraMarker`(含 `channelId``latestEvent*` 等)。
## 4. 迭代计划(按优先级)
### 阶段 A — 闭环与首屏体验(P0)
- [x] 数据流 ↔ 2D **视图模式** `localStorage` 记忆(`desktop-view-mode.ts`,键 `desktop-view-mode`
- [x] **浏览 / 编辑** 模式:浏览下禁止改墙/摄像头、禁止绘制;编辑下保持现有能力(`floor_plan.storage``desktop-floor-plan-interaction-mode`
- [x] 绑定通道的摄像头:**跳转录像页** `/playback/detail?cid=…&date=…`(与 `recordings.tsx` 一致,见 `floor_plan.playback.ts`
- [x] 悬浮卡片:视口内**防裁切**、「打开录像」按钮;缩略图 `onError` 打日志
- [x] 浏览模式:单击用于选中(看侧栏),**不**自动整页跳转;跳转统一走「打开录像」
### 阶段 B — 信息效率(P1)
- [x] 单选摄像头时侧栏展示**最近一次 AI 事件**(与 hover 共用 `getLatestCameraEvent`
- [x] 通道名称**搜索**:未匹配摄像头在画布上淡化(`opacity`
### 阶段 C — 增强(P2+
- [x] 通道在线/离线:由 `FindPlannerChannelOptions` 拉平的 `isOnline` 映射到已绑定 `channelId`(画布描边绿/红;侧栏与悬停卡片展示文案)
- [x] 触控/缩放:画布容器 **滚轮** 以指针为锚缩放;**双指 pinch** 以两指中点为锚缩放(与工具栏缩放共用 0.35–3.2 范围)
- [x] 平面图内已绑定通道的**最近事件预取**:无专用批量接口时,用 `FindEvents``started_at desc` 分页,在客户端为每个 `cid` 保留首见的一条并写入缓存与 `CameraMarker.latestEvent*`(与单通道查询共用 `MapEventToLatestChannelEvent`);绑定集合变化时重新预取
### 阶段 D — 跨页跳转(延续原 MVP「告警」方向)
- [x] 悬停卡片与侧栏 **「打开告警」**:跳转 `/alerts?cid=…`,告警页读取 query 并预选通道筛选(与平面图 `channelId` 一致)
- [x] 跳转实现使用 **`<Link to={{ pathname, search }}>`**(与 `buildPlaybackDetailTo` / `buildAlertsTo`),避免在 `basename`(如 `/web`)下 `navigate` 字符串与 query 解析不一致导致「点了不跳」
- [x] 悬停卡片 **Portal + `fixed` + z-index 高于 FAB**,离开摄像头 **短延时清除** + 移入卡片取消清除,避免被右下角菜单占位挡住或移向按钮时卡片消失
### 阶段 E — 前端体验增强(不接后端存储)
- [x] **首次引导**`Modal` + `localStorage``desktop-floor-plan-guide-dismissed`;顶栏地图钉可再次打开
- [x] **筛选导航**:匹配列表 **上一条 / 下一条**(自动选中并居中)、**框入全部匹配**(仅缩放至匹配摄像头包围盒)
- [x] **事件可信度**:侧栏 **刷新**`clearLatestCameraEventCache` + 重拉);悬停卡片与侧栏展示 **事件发生相对时间****数据拉取相对时间**30s tick
- [x] **鸟瞰小地图**`FloorPlanMinimap` 点击平移视口;顶栏 **框选全部已绑定摄像头**`zoomToFitCameras`
### 阶段 F — 纯前端续(备份与快捷)
- [x] **布局 JSON 导出 / 导入**:顶栏下载/上传,`floor_plan.export.ts` 包装版本与时间;导入后清空事件缓存并重置撤销栈
- [x] **浏览模式筛选快捷键**`[` / `]``PgUp` / `PgDn` 切换匹配,`F` 框入全部,`Esc` 额外清空筛选关键词
- [x] **小地图拖拽**:轻点仍居中,移动超过阈值则按像素平移主视口(与 `view.x/y` 一致)
### 阶段 G — 移动端适配(≤767px)
- [x] **布局**`flex-col` + 画布占满剩余高度(`min-h-0`);侧栏自 `md` 起固定右侧,小屏改为 **底部 Drawer**(浮动按钮打开)
- [x] **顶栏**`sticky` + **横向滚动**,避免按钮换行压扁画布;桌面仍为 `absolute` 浮动条
- [x] **提示条**:小屏缩小字号、限制高度可滚动,避免占满屏幕
- [x] **小地图**`compact` 缩小尺寸并抬高 `bottom`,避让底部提示与安全区
- [x] **桌面壳**`100dvh` 避免移动浏览器地址栏导致高度跳动
- [x] **画布**`touch-pan-y touch-pinch-zoom` 声明 pinch 手势
- [x] **触摸拖动**document 级用 `pointermove`/`pointerup` 跟踪(替代仅 mouse),浏览模式小屏空白处单指拖动平移视口
## 5. 关键文件
| 文件 | 职责 |
|------|------|
| `app/pages/desktop/desktop.tsx` | 数据流 / 2D 切换、视图模式持久化 |
| `app/pages/desktop/floor_plan.tsx` | 2D 主编辑器 |
| `app/pages/desktop/floor_plan.storage.ts` | 平面图与浏览/编辑模式本地存储 |
| `app/pages/desktop/desktop-view-mode.ts` | 数据流 / 2D 视图记忆 |
| `app/pages/desktop/floor_plan.playback.ts` | 录像详情 URL 与列表页对齐 |
| `app/pages/desktop/floor_plan.alerts.ts` | 告警页深链接 `/alerts?cid=` |
| `app/pages/alerts/alerts.tsx` | 支持 URL `cid` 初始化通道筛选 |
| `app/pages/desktop/floor_plan.events.ts` | 最近 AI 事件查询、缓存与批量预取 |
| `app/service/api/event/event.ts` | `MapEventToLatestChannelEvent` 与单通道/批量字段一致 |
| `app/components/desktop/camera-hover-card.tsx` | 悬停卡片 |
| `app/components/desktop/camera-binding-panel.tsx` | 绑定与参数、侧栏最近事件展示 |
| `app/components/desktop/floor-plan-minimap.tsx` | 左下角鸟瞰与视口框 |
| `app/pages/desktop/floor_plan.relative-time.ts` | 事件/拉取时间的相对文案与绝对时间格式化 |
| `app/pages/desktop/floor_plan.export.ts` | 导出包装与导入解析(兼容裸 `FloorPlanState` JSON |
## 6. 后端参考
事件、通道等与 [gowvp/owl](https://github.com/gowvp/owl) 对齐;前端通过现有 `FindEvents` / `FindPlannerChannelOptions` 等调用。
## 6.1 若需后端配合(交接用,当前未实现)
以下能力前端已用现有接口「尽力而为」;要进一步降延迟、减流量或做多端同步,建议 owl 侧迭代:
1. **按通道批量查询最近事件**
- **问题**:现用全局 `FindEvents` 分页在客户端按 `cid` 归并,通道多时页数多、延迟高。
- **建议**`POST /api/.../events/latest-by-cids`body `{ cids: string[] }`,返回每通道一条最新记录(与现有单通道字段一致)。可选 `since` 支持增量。
2. **平面图布局云端存储**
- **问题**`localStorage` 无法跨浏览器/团队共享,清缓存即丢。
- **建议**:资源模型如 `floor_plan``tenant_id``name``state_json`(或版本化 blob)、`updated_at`REST `GET/PUT` 或按用户默认布局单例。
3. **导出 / 导入 JSON(纯前端也可做)**
- 若需审计与备份,可增加后端「上传布局快照」存对象存储,与 2 类似。
## 7. 验收清单(2D
- [x] **浏览 / 编辑与工具可见性**:浏览模式下隐藏仅编辑用的顶栏工具(绘制、撤销、剪贴板、编组、重置布局)与侧栏快捷预设及批量/单墙编辑按钮,避免满屏禁用态;绑定面板内通道绑定、朝向滑块与删除摄像头在浏览模式下亦隐藏,仅保留只读摘要与提示;编辑模式下仅显示当前可用的撤销/重做、复制/粘贴等(无选择时不占位)
- [x] 刷新后仍保持上次「数据流 / 2D」选择
- [x] 浏览模式下无法误改平面图;编辑模式可完整编辑
- [x] 已绑定通道的摄像头可从平面图进入录像详情(当日日期)
- [x] 悬停卡片在边缘不被裁切;侧栏可看到与 hover 一致的最近事件信息(有通道时)
- [x] 滚轮 / 双指缩放可用;已绑定通道显示在线状态(列表能解析时)
- [x] 首次进入可看到引导(可关闭并记忆);筛选支持匹配间跳转与框入全部匹配;侧栏可刷新事件并显示相对时间;小地图可点击导航
- [x] 可导出/导入布局 JSON;浏览模式下筛选快捷键可用
---
*文档版本:与仓库 `desktop_2d_plan_todo.md` 同步更新。*