42-associated-device-layer.md 10 KB

42: 关联监测设备临时图层

进度

整体验收复核重开:刷新/快照失效撤层与详情重载链尚未满足。已有同编码重绘修复当前回归通过,仍需真实复验。证据:verify/artifacts/t48/acceptance-status.md。

Type: implementation Status: ready-for-agent Blocked by: 41 Labels: needs-triage

What to build

按规格 14 接入选中监测点后的关联监测设备临时图层。地图摘要继续只包含监测点与未关联设备;关联设备不写回摘要序列、分页、默认图例或摘要计数。地图点击和台账选择都从同一监测点选择语义启动设备加载,并与点位定位并行;设备数据到达即可渲染,不等待相机动画结束。

后端 #69 已发布:有 snapshotAt 时详情与地图共享同一快照;设备编码集合以地图快照 deviceCodes 为准,坐标只认设备自身 longitude/latitude/coordinateValidation.renderable。无坐标、非法、未校验、归属不明、详情失败或当前快照不一致的设备继续出现在清单中,并显示待确认/不可用原因,禁止复制监测点坐标或人工偏移。现网 UNVERIFIED_COORDINATE 的正式边界是清单-only。

Acceptance

  • 选中监测点后关联设备图层自动加载;地图与台账入口行为一致。
  • 使用受控的坐标准入有效样例验证独立图层渲染与拾取;现网后端 UNVERIFIED_COORDINATE/renderable=false 时只显示清单及原因,不用临时样例冒称正式设备已能上图。
  • 有效设备只进入独立临时图层,设备身份同时携带 deviceCode 和所属 monitoringPointCode,不冒充 pointCode。
  • 关闭、换点、刷新、快照失效时旧图层立即撤下;迟到响应不能覆盖当前选择。
  • 同一 snapshotAt 翻页不重建或闪烁设备图层;快照查找逐页进行,第一页没有不能判定点位不存在。
  • 设备总数来自当前快照去重 deviceCodes;详情独有/快照独有设备分别标记不一致或待确认,不静默丢弃。
  • 总览/运行监测显示全部坐标准入有效设备;基础设施隐藏;预警处置只显示设备自身 ALARM/WARNING,未知状态待确认。
  • 清单保留全部关联设备,明确区分已上图、无地图位置、模式隐藏、待确认/失败;摘要图例和关联设备图例/计数分开。
  • 纯逻辑覆盖集合分类、快照生命周期、计数互斥;外壳走查覆盖地图/台账入口、关闭、换点、分页和降级。

Out of scope

  • 设备 hover/选中双向反应、资产选择、状态特效、重叠展开、完整模式计划的独立实现。

进度:100%(2026-09-29 收口)

已完成并关闭。 逻辑闸门 37/37、变异测试 19/19 全部打红、真机走查已执行(见下), 全量零依赖闸门回归绿。

交付物

  • domain/deviceLayer.js(新):集合分类(六类互斥:drawn/no-location/hidden/pending/ inconsistent/unavailable)、快照生命周期(总数只认当前快照去重 deviceCodes; 快照独有→待确认、详情独有→不一致且禁止上图)、互斥计数与独立图例、跨端点风险提示。
  • stores/deviceLayerStore.js(新):合成点。它读 mapStore 的当前快照 deviceCodes(总数依据) 与 detailStore 的 devices[](状态与设备级坐标),按 domain 判定后交地图服务。 两侧都不为自己长出对方(票 10 的 F4、票 02 的层次纪律)。
  • services/cesiumEngine.js:syncAssociatedDevices / readAssociatedDevices / clearAssociatedDevices / pickDeviceMarkerAt / hasDeviceMarker + 独立数据源 cockpit-associated-device-markers(与摘要 cockpit-point-markers 分开)。
  • services/mapService.js:syncAssociatedDevices / clearAssociatedDevices / getAssociatedDeviceState + 宿主读数 data-map-devices(-plan)(与摘要 data-map-markers* 分开)。
  • domain/pointDetail.js:设备卡片带出设备级坐标与校验(后端 #69 已交付)。
  • pointSelection.js:统一选择入口在打开详情前先出一次设备计划(不等详情、不等镜头)。
  • CockpitShell.vue:四类订阅(选择 / 详情到达 / 快照变化 / 一级模式)+ 卸载拆监听与复位。
  • components/PointDetailCard.vue:关联设备清单(保留全部、每行标注互斥归类)+ 独立图例。
  • mock:默认场景照抄现网边界(设备统一 UNVERIFIED_COORDINATE/renderable=false); 新增 device-layer 受控有效坐标样例(两台设备带自身有效坐标,且地图 deviceCodes 与详情 devices[] 一致)。
  • 证据:verify/t42-device-layer.mjs(37/37)+ 变异 19/19 全部打红。

三条关键取舍(都来自已 resolved 的规格 14 / 决策票 05,不在本票发明)

  1. 总数只认当前快照去重 deviceCodes,不拿详情统计或卡片数冒充 —— 详情不携地图快照的 snapshotAt、还可能复用缓存,两边可能不同版。所以「快照独有」与「详情独有」必须分开: 前者待确认、后者标不一致且禁止上图,两边都不静默丢弃。
  2. 坐标准入只认设备自身 coordinateValidation.renderable(票 07 的唯一判据): 前端不重算经纬度范围、绝不用监测点坐标代替设备坐标、不人工偏移(CONTEXT.md 明令禁止)。 现网无可信校核源 → 正式边界是清单-only,本票照抄这个边界。
  3. 数据可用性先于模式可见性(实现时抓到并修掉的真问题):若先判模式,一台「坐标被后端否决」 的设备在预警处置里会显示成「当前模式隐藏」,值班人员会以为"切到总览就能看到它"—— 而它任何模式都上不了图。说成模式隐藏是把数据问题推给了模式,差额就解释错了。

真机走查(已执行):抓到并修掉 1 处真缺陷

本机 @puppeteer/browsers 是空目录(票 37 记录的既有环境缺陷),故按票 36/37/41 成例 改用 DSH 自带浏览器真实驱动(yarn dev @8000,真实 public/cockpit/config.json)。

修掉的缺陷:UI 把「清单行数」当成了「关联总数」。 真机读数暴露:总数显示 2 而当前快照 只有 1 台设备 —— 多出来的是「详情独有」那一行(规格明确它不计入总数)。 修:store 单独持有 total(=当前快照去重 deviceCodes 条数),与 rows.length 分开; 界面两个数都显示且各有明确含义。已补断言 B1b-total-is-not-row-count 钉住。

实测证据(真实浏览器,与验收逐条对应):

  • 受控有效坐标样例:两台设备真的画在独立图层上(onMap=2),实体 id 形如 device|MP-001|EQ-001,属性同时带 deviceCode + monitoringPointCode、不含 pointCode (不冒充监测点);摘要标记仍为 2(data-map-markers=2)、设备另计(data-map-devices=2)。
  • 现网降级边界(清单-only):默认场景下设备统一 UNVERIFIED_COORDINATE/renderable=false → 清单保留并标 no-location、引擎 0 台、总数 1、清单 2 行(inconsistent 那行不计入总数、 不上图)、跨端点风险提示出现、摘要标记仍 2。
  • 关闭即撤下:点关闭 → 设备层 onMap=0、计划清空、宿主读数归零,而摘要标记仍 2(互不牵连)。
  • 换点:MP-001 → MP-002 后只剩 B 的设备(归属 pointCode 正确),A 的不残留。
  • 独立拾取:pickDeviceMarkerAt() 只认本图层带 deviceCode 的实体并回身份; 设备优先于监测点(票 15 的优先级)。

未覆盖项(如实记录):走查时浏览器标签 document.hidden===true,rAF 被冻结、Cesium 不渲染 (票 37/41 记过同一环境事实),因此依赖渲染的 scene.pick 在本次环境下连监测点标记也拾不到 (已用"连 pointHit 也为 null"的对照确认是环境而非本票缺陷)——「真实鼠标点设备点」这条 双向联动入口的走查归票 43(它正是双向对应的实现票,且 pickDeviceMarkerAt() 的接缝已就位)。 建议维护者在前台标签页复跑一次以补该条观感。

与下游票的边界(不在本票实现)

  • 票 44:设备形状/尺寸/资产接缝与独立设备状态词表。本票的设备标记用中性占位符号 (shape 由调用方给,默认 circle)与 14px 尺寸(小于监测点的 18px),不实现状态词表。
  • 票 46:完整四模式图层计划(domain/modeLayerPlan.js)与图例合成。本票只实现 单点位的模式可见性(isVisibleInMode),不做全图矩阵。
  • 票 47:设备状态特效。
  • 票 43:面板与三维设备点的双向对应(hover/选中/引线/定位)。

回归

零依赖逻辑闸门全绿(t01/t03/t04/t05 254/t06/t07 39/t08 44/t09/t10 57/t11/t12/t13/ t14/t15/t16/t17/t18 71/t19/t21/t21-view/t29/t30/t36/t37/t38/t39/t41 46/t42 37)。 两处红与本票无关:① t28-fill-container.mjs 需 puppeteer,而本机 @puppeteer/browsers 是空目录 (既有环境缺陷);② 某次运行中 t05 的 C8-real-attaches-credential 一度红 —— 经核实是并发会话 正在改 services/cockpitApi.js / mapApi.js(本票改动清单里没有这两个文件),随后复跑已恢复绿。

按 AGENTS.md:本会话未跑 build(真机走查是维护者本轮明确要求才执行的)。

下一步

  1. 维护者在前台标签页复跑一次,补「真实鼠标点设备点」的双向联动观感(或直接由票 43 覆盖)。
  2. 43(面板与三维设备点双向对应)、44(设备位置符号与状态词表)、46(模式图层计划) 均已解除阻塞,可并行。

Comments

local — 2026-10-10T08:10:42.403Z

整体验收审查:刷新等待首屏期间旧设备层仍在;快照失效未改变batchUpdatedAt时不撤层;缺重找点位、强制重取详情及完整找不到后关闭链。另同编码坐标/状态未重绘已在整体验收当前工作区修复(t48-linkage-invariants),尚待提交与真实样本回验。当前票因刷新生命周期未满足重新打开,先诊断再实施。