# 09: 点位状态图例与标记 **What to build:** 将后端解析后的监测点状态渲染为地图标记、颜色和图例。前端不重算点位状态,不把事件等级色混用为点位状态色。 Blocked by: 08 Status: resolved Labels: ready-for-agent - [x] 监测点标记按后端返回状态渲染。 - [x] 正常、预警、报警、处置中工单、离线/无关联设备状态均可表达。 - [x] 每种颜色都有文字或形状辅助,不单独依赖颜色。 - [x] 地图图例与标记状态一致。 - [x] 有状态到视觉表现的单测。 ## 进度:100% **已完成并关闭(2026-09-18)。** 逻辑闸门 **38/38**、真机走查 **28/28**;回归 16 个既有闸门全绿 (t01 20/20、t04 9/9、t05 179/179 + 10/10、t06、t07 39/39 + 20/20、t08 44/44 + 16/16、 t21 9/9 + 10/10、t28 7/7、t29 6/6、t30 7/7)。 ### 交付物 - 新增 `src/modules/cockpit/domain/pointStatus.js`:**状态 → 视觉表现的唯一一张表**。 六个后端状态(`ALARM/WARNING/WORK_ORDER/NORMAL/OFFLINE/EMPTY`,标签与优先级逐字照抄后端 `CockpitMonitoringPointStatus`)各带 `色键 + 形状 + 文字`;另有 `UNKNOWN`(状态未发布) 与 `UNASSOCIATED`(无关联设备)两条。地图标记、地图图例、`markerSvg()` 图片都从这一张表取, 所以「图例与标记一致」是结构性的,不靠两边各自小心。 - `services/cesiumEngine.js` 新增点位标记层:`CustomDataSource('cockpit-point-markers')` + billboard(形状 SVG data URL、`CLAMP_TO_GROUND` 贴地形)。引擎层只认 `shape/tone`,不认识业务状态名。 - `services/mapService.js` 新增 `syncPointMarkersForSummary()` / `getPointMarkerState()` / `clearPointMarkers()`;语义色**从 `.cockpit-shell` 的计算样式读** `--lv1..--neutral`, 域层与引擎零色值(票 06 的单一口径)。 - `components/MapCanvas.vue`:地图图例换成**点位状态图例**(8 行,每行形状 + 文字 + 计数), 标记随分页批次增量重画;`StatusTag` 增可选 `shape` 道具(不传仍是票 06 的圆点)。 - `mocks/contractMocks.js`:新增 `point-statuses` 场景(六态 + 未关联设备 + 一个前端不认识的状态, 全部可上图)。**默认样例一个字节未动**,所以票 07/08 的走查数字(`2,4,5` / 可上图 2 · 不上图 3)原样成立。 ### 两个只有真机才暴露的 bug(都是视觉探针抓到的,走查当时反而绿) 1. **Cesium 的 `DataSourceCollection.add()` 是异步的**(`Promise.resolve(ds).then()` 里才 push)。 同一 tick 内「先写后读」会建出**两个数据源**:写进未注册的 A,再从新建的空 B 读回 0 个。 症状极具迷惑性——模块计数与 dataset 都说 8,组件渲染却是「点位标记 0」, 而晚一点的 DEV 把手调用(A 已注册)又读回 8,同一页面两套答案。 修法:`WeakMap` 按 viewer 缓存数据源实例。 2. **补画重试封顶 10 秒**:引擎冷启动(动态拉 Cesium 分包 + 地形/影像)比装载器慢, 超时后第一批点位再也没画上,只有用户点「加载下一页」才会重新触发。 修法:退出判据改成**引擎终态**(ready/failed/disabled/unavailable),不再是"试够次数就放弃"。 第 2 条同时暴露了走查的盲区:它一路在点分页按钮,所以永远能画出标记。 为此新增走查块 **H**:**一次都不点**,只等引擎 ready,要求标记自己出现。 ### 对抗式复验(每条断言都确认过能变红,不是恒真) - 把 `toneColors()` 改成恒返回一个颜色 → C2/C3 红(**第一版 C2 比的是"图片是否不同",而图片里含形状, 所以它当时假绿 25/25**;已改成把颜色从 SVG 里单独抠出来比,并要求逐个等于 token 实测值)。 - 把图例截成 5 行(标记仍 8 个)→ D2/D3/G1/H2 红。 - 把 `StatusTag` 的形状去掉 → D4/D6/D7 红。 - 把所有状态折叠成 `NORMAL` → B1/B2/B3/B5/C4/C7/D3/D5 红。 ### 口径说明(供后续票对齐) - 票面写「处置中工单」,后端枚举的 label 是**「工单处置」**;本票用后端的词,避免前端另造一套业务词汇。 - 「离线」与「无设备」同为中性灰,靠**形状**区分(空心圆 vs 空心方块),并各自带文字。 > **2026-10-08 就地修订(由[蓝湖素材替换票 05](../../lanhu-cockpit-asset-replacement/issues/05-point-device-marker-mapping.md) Q22=1 裁定)**:正式素材替换后,「无设备」不再使用 `hollowSquare` 几何形状,改为「**镂空徽标母版 `T_MarkPoint_White` + 降饱和降亮度 + 不使用内层图标**(Q25=C),并保留文字标签「无设备」」。本行原「空心方块」口径**被取代**;本票其余口径(六态、优先级、色键、颜色不是唯一线索)不变。 - 地图标记设了 `disableDepthTestDistance: Infinity`:状态点不因地形/建筑遮挡而消失(大屏值守优先)。 若将来要"被楼挡住",改这一处即可。 - 地图上原来的**事件四级图例已移除**(票 09 正文明确不许混用)。事件等级图例归票 13/19; 票 14「事件定位」要把事件画到地图上时,需自己带一份事件图例,**不要**直接复用点位状态那 8 行。 ### 后续关联监测设备图层的图例口径(决策地图票 05,非本票已交付功能) 本票八行图例继续只解释默认摘要的监测点状态与未关联设备;新增的关联监测设备临时图层应有独立设备图例,且设备图例只计当前模式实际绘制的设备。`data-map-markers*` 与“点位标记”数仍只计当前模式可见的摘要标记,不计设备图层;摘要分页总数不混入关联设备。该图层及模式筛选的实现由后续规格负责,本票原有图例验收与完成记录保留。参见[决策地图票 05](../../cockpit-point-locate-and-device-link/issues/05-device-point-layer-trigger-and-lifecycle.md)。 ### 遗留 - 点位聚合(CONTEXT.md「点位聚合」/ ADR 0002)不在本票验收内:同一位置多点目前各画各的, 没有聚合与展开。本票只保证状态词表与图例一致。 - 地图标记的点击选中归票 10(`entity.id` 已按 `point||` 建好,可直接拾取)。 ## Answer **点位状态 → 视觉表现收成一张表(`domain/pointStatus.js`),地图标记与地图图例同源于它; 前端只渲染后端 `pointStatus`,认不出的状态如实落「状态未发布」而不猜成正常; 每个状态同时有形状、色键与文字,颜色不是唯一线索;事件等级色不再出现在地图图例上。**