52-untitled.md 16 KB

邻域设备示意挂载与增强面板内部详情

What to build

在邻域增强场景显示真实监测设备模型,按行业在管道固定示意槽位摆放并可点击查看内部设备详情。真实设施关系优先;无关系但合法坐标的邻近设备可挂同业最近管段,标“邻近设备·示意安装”。无合适管段独立显示,无坐标无关联仅列清单。

Acceptance criteria

  • 核验并补齐邻域设备读取来源及设施/井关系;不能把所选监测点设备当附近全部设备。
  • 真实设备ID与父监测点身份保留,真实关联优先于空间近邻,networkId按真实主键匹配。
  • 同业固定槽位示意布局、无位置清单、关系/布局提示,绝不创建设备或改绑定/源坐标。
  • 设备模型点选打开增强面板内部详情,复用真实详情接口;场景和相机保持。
  • 在线、告警及读数真实显示,缺失/失败/过期/重试/换选取消正确;不能从附近设备推导管道健康。
  • 同业近邻、悬空关系、无坐标、缺来源/部分覆盖、设备点击至详情和销毁行为回归。

Blocked by

51

Context

完整已确认方案为本effort local-network-enhancement-spec.md。历史gas_pipe_point_device_rel、manhole_device_rel不等于equipment_point_rel;当前前端适配未完整暴露设施关系,实施需核验契约,缺关联按用户允许的示意降级,不得伪报完整覆盖。

设施/井关系核验结论(2026-10-21 实测)

第 1 条验收的「核验」部分已按免鉴权 cockpit 接口逐端点确认;「补齐」部分需要后端新增契约,前端无法自补。证据如下。

设备读取来源(已补齐,可满足)

来源 端点 状态
当前快照全部监测点 /map-snapshot → monitoringPoints[].deviceCodes 可用,7 点全部带 deviceCodes
每个点位的设备卡 /monitoring-points/{pointCode} → devices[] 可用,含 deviceCode/坐标/状态/deviceStatus
未关联设备 /map-snapshot → unassociatedEquipment[] 可用,8 台
设备详情 /equipments/{deviceCode}/detail-aggregate 可用

结论:读取来源不是「所选监测点的设备」,而是当前快照全部点位 + 独立设备,符合验收第 1 条的前半句。

设施/井关系(契约缺口,无法前端补齐)

探针 结果
/map-snapshot 的 unassociatedEquipment 带 networkId 0 / 8
/map-snapshot 的 monitoringPoints 带 networkId 0 / 7
/monitoring-points/{code} 的 devices[] 带 networkId 无该字段
/equipments/{code}/archive 的关系字段 无(只有档案属性)
/api/cockpit/v1/device-boundary 6762 条 facilities + 9 条 devices,两份互不相连的扁平清单,无关系边
cockpit 免鉴权 Swagger 路径清单中的设施/井关系端点 不存在(只有 device-boundary/archive/detail-aggregate/metrics/events/work-orders)
/api/manhole/device/list/{id} 免鉴权可用,但实测返回 []
/api/gas-pipe-point/device/list/{id} 免鉴权可用,但实测返回 []
/api/manhole/device/rel/list/{id} 401 认证失败(非免鉴权面)

/infrastructure/geometry 侧 6766 个 feature 全部带非空 networkId,但实测 networkId === sourceId(即设施自身主键),不是「设备→设施」的关联键。因此当前不存在设备侧可用的真实设施关联主键。

这意味着:domain/enhancementDevices.js 的「真实 networkId 匹配优先」分支在真实数据下永远不会触发;真实运行时不变量是「同业邻近示意」或「无同业管段 standalone」。该分支有构造数据回归(t52-device-plan.mjs),但从未被真实载荷触发过——这是契约现状,不是代码缺陷。

归类

本票同时含两类无法由 AI 闭环的事项:

  1. 外部契约依赖——「补齐设施/井关系」需要后端在免鉴权 cockpit 面新增设备→设施关系端点(或让 map-snapshot 的监测点/设备带出真实关联主键)。前端不能凭空造关系,按规格也不得把 code 当关联主键。
  2. 需人工测试——邻域场景中设备模型是否可辨、槽位是否合理、点选详情是否符合预期、以及 8 倍显示下设备是否可见。

AI 不代劳的原因:AGENTS.md 禁止自动 build/dev/浏览器截图;后端仓库与权限不在本会话交付范围。

给维护者的实施清单

A. 现场视觉验收(只需你本人执行)

  1. 你启动 yarn dev,打开 http://127.0.0.1:8000/#/cockpit。
  2. 拾取一条管道进入「地下管线详情视图」。
  3. 逐项目检:
    • 右侧「监测设备」区是否与「附近管道状态」分离显示、不被长列表挤走;
    • 场景中是否有可辨的设备图标/模型,点击后是否打开内部设备详情面板;
    • 设备清单点击是否聚焦到场景设备并打开同一详情;
    • 设备标注是否明确写「邻近设备 · 示意安装」(而非暗示真实安装位置);
    • 无坐标设备是否只出现在清单、没有被摆到伪造位置。
  4. 检查点:图标大小是否合适、密集时是否互相遮挡、详情面板是否遮挡关键信息、关闭详情后场景是否保持。
  5. 边界与回归:换选管道、切换 25/50/100 米、切换全局行业筛选——确认设备清单随之变化且旧详情被取消。

B. 后端契约补齐(需后端负责人,非本会话)

要让「真实设施关系优先」在真实数据上生效,需要下列之一:

  1. 在免鉴权 cockpit 面新增关系端点,返回 { deviceCode, facilityCode | networkId, relationType };
  2. 或让 map-snapshot 的点位设备卡 / monitoring-points/{code} 的 devices[] 带出真实设施关联主键;
  3. 或把 manhole_device_rel / gas_pipe_point_device_rel 的读取面纳入免鉴权 cockpit 契约。

补齐后本票的 linked 分支会自然生效,前端无需改动(domain/enhancementDevices.js 已按真实主键匹配,且明确禁止用 code 冒充)。

在此之前:系统按维护者已批准的「同业邻近示意」降级运行,界面如实标注「邻近设备 · 示意安装」,不宣称真实绑定。

C. 不在本票范围

邻域裁切(51,已关闭)、窨井剖切(53)、真实管径与材质(54)、场景设备图标细化(58)、按设备类型取指标(56)。

可复跑的离线证据

  • node .scratch/cockpit-shell-panel-layout/verify/t52-device-source.mjs(读取来源、覆盖缺口、渐进发布)
  • node .scratch/cockpit-shell-panel-layout/verify/t52-device-plan.mjs(真实 ID 优先、邻近示意、无位置清单、旧响应隔离)
  • node .scratch/cockpit-shell-panel-layout/verify/t52-device-pick.mjs(真实 Three 射线派发设备身份、拖拽不误点)
  • 整套:node .scratch/cockpit-shell-panel-layout/verify/t50-53-local-enhancement.mjs(12 个脚本)

进度

  • 2026-10-16 代码与离线回归完成,转 ready-for-human。加载当前快照全部监测点详情(4 并发)及独立设备,保留真实父点/ID;摘要未齐、缓存截断、详情失败/缺/额外设备均报 partial 并可重试。
  • 固定槽位按管段/裁片稳定分组,模型不改源坐标,未准入且无关系仅清单。Three 射线派发设备身份并尊重首交点遮挡;内部复用 EquipmentDetailSections 与真实 detail-aggregate 接口,打开详情不重建场景。范围移除 reconcile、刷新开始 sync invalidate、模式可见性与异常集合、旧详情/source token 隔离已实现。
  • 2026-10-21 按 /wayfinder 接手(上游 #51 已关闭,阻塞解除):复跑 t52-device-source/t52-device-plan/t52-device-pick 全部通过;实测核验设施/井关系端点,确认免鉴权 cockpit 面无设备→设施关系契约(map-snapshot 设备侧 networkId 0/8、点位 0/7,device-boundary 只有两份扁平清单,manhole_device_rel 读取需 401)。据此勾选第 1 条验收的核验部分,并把「补齐」明确为后端契约依赖写入正文。
  • 记录:正文曾被 deck_issue_patch 传入空 body 擦除,已按原文恢复;后续只读上报。

2026-10-22 维护者四条反馈修正 + 后端契约落地

维护者现场验收后给出 4 条修正(A)并批准后端补契约(B),均已在本会话完成,提交 c12f774(前端)与 83bd5ee(后端),均已推送。

# 反馈 处理
A1 设备区与管道状态已分离,但附近管道状态要分页 每页 8 条 + 上一页/下一页 + 页码;换选/邻域变化回到第 1 页。t23-click-flow 断言 12 条时只渲染 8 条且设备区仍在
A2 场景设备图标没有用地图同款,要保持一致 Three 场景不再自绘图标:改为 planMarker + renderMarker(与一张图同一合成链路:水滴母版 + 行业内层 + 白描边 + 状态色),产物作 Sprite 贴图,尺寸沿用其 draw
A3 详情面板要与监测设备坐标点一致,点击后在三维场景中浮动 详情从右侧栏移出,改为浮在三维场景之上的独立面板(可单独关闭,不动相机/场景)
A4 无坐标设备在地下管线详情视图中应隐藏 改为直接跳过,不再进清单;主图台账仍可查

顺带修掉一个真实缺陷:改造图标点选时曾丢失每次点击的 setFromCamera,导致拾取依赖上一次射线的残留状态。已恢复按本次坐标重新投射;图标点选用与图标同尺寸的透明代理平面命中(Sprite 在嵌套缩放下 raycast 不可靠——同一图标最小用例能命中、放进场景就 miss)。

B 后端契约(已上线):GET /api/cockpit/v1/device-facility-relations(免认证只读,沿用既有 permitAll,未放宽安全边界;commit 83bd5ee)。前端新增 services/deviceFacilityRelations.js 消费它,关联优先级变为真实设施关系 > 载荷 networkId > 同业邻近示意。

⚠️ 必须如实记录的数据现状:契约已就绪,但当前真实可回联关系为 0 条。实测响应:manholeRelationRows=6、gasPipePointRelationRows=4、returnedRelationCount=2,其中 skippedManholeFacilityMissing=4(4 条存的是设备 id 不是窨井主键)、skippedGasPipeNetworkMissing=4(管点 network_id 在管段表里不存在,悬空)、deviceCodeUnresolved=2(2 条 equipment_id 在 equipment_base 查不到,deviceCode 为 null)。因此界面当前仍标「邻近设备 · 示意安装」,不是真实绑定;要真正点亮真实关联,需运维补数据(管点 network_id 指向真实管段、关联表 equipment_id 指向 equipment_base 主键)。

验证:t52-facility-relations(真实关联命中/设施编码不匹配降级/空索引降级/只回联齐全行/取数失败降级)、t52-device-source、t52-device-plan、t52-device-pick、t55-detail-usability、t55-device-loading、t56-real-water-device、t56-device-metrics、t23-click-flow、t23-sfc-compile、t09-point-status(38/38) 与整套 12 脚本全部通过。按 AGENTS 未跑 build/dev/browser。

范围自查:mapService.js 与 markerPlan.js 带其它在制品改动,本票未提交这两个文件(Three 服务自带同值兜底色表,避免触碰他人工作);未改任何后端既有文件。

2026-10-22 二次反馈:颜色状态与类型图标语义不同步(已修,ba5041a)

维护者确认场景已用同款图标后指出:颜色状态与中间的类型图标仍未同步。根因是 Three 侧没走主图的两条语义规则:

  1. 颜色:主图给 planMarker 显式传设备状态表的色键(deviceVisualForStatus():ALARM→lv1、WARNING→lv2、WORK_ORDER→lv3、NORMAL→lv4、OFFLINE→point-offline、认不出→point-unknown)。我此前没传 tone,于是落到 markerPlan 的点位聚合态默认表——那里 OFFLINE/UNKNOWN 都是 neutral,所以离线设备与主图不同色、未知态被画成灰色。
  2. 类型图标:内层图标按 industry 选(gas/water/drainage/manhole)。设备卡常无 industry,主图规则是继承所属点位行业;服务层已按同一规则落好(device.industry || point.industry),但 Three 侧此前没把这条链路当唯一来源。
  3. 母版形状:无 pointCode(未关联设备)应为镂空母版,与主图一致。

修法:新增唯一裁决点 deviceMarkerPlan(device) —— 统一由 deviceVisualForStatus() 取 tone、按 industry 选内层、按 pointCode 决定镂空/实心,再交给同一个 renderMarker。回归 t52-device-pick 逐项锁死:五态 + 未知态色键、四行业内层图标、无行业不造图标、有点位=实心/无点位=镂空。

验证:t52-device-pick、t52-facility-relations、t52-device-plan、t52-device-source、t55-detail-usability、t55-device-loading、t56-real-water-device、t23-click-flow、t23-sfc-compile、t09-point-status 与整套 12 脚本全部通过。按 AGENTS 未跑 build/dev/browser。

2026-10-22 三次反馈:点击设备后的镜头定位运动效果(已实现,0d844bb)

维护者:「点击点位后的镜头定位运动效果也需要实现。」此前 focusDevice 是直接改写 target/distance 再重绘 —— 瞬移,没有运动过程。

实现:FLIGHT_MS=620ms 逐帧缓动(ease-in-out cubic),从当前 target/distance 插值到目标并每帧重绘。取消策略:用户 pointerdown 拖拽或滚轮接管镜头时立即 cancelFlight(),销毁时同样取消,不与用户抢相机。

顺带修掉一个定位漂移:目标点原先取「设备组整体包围盒」中心,而图标是按屏幕像素恒定尺寸缩放的——飞行途中图标变大,包围球中心随之移动,镜头会「飘」。改为取稳定几何(device-body)的包围球心。

可注入接缝:scheduleFrame / now 两个参数,使脱浏览器回归能逐帧推进而不是只看终态。

t52-camera-flight.mjs 断言:①受理瞬间不瞬移且已排帧;②半程已移动但未到终点(证明是连续运动);③到期镜头方向正对设备中心(用方向点积,不能用距离——lookAt 只取单位向量);④拖拽接管后不再排新帧;⑤销毁后停止推进。全套回归通过。

Status: ready-for-human Assignee: codex Type: task Blocked by: #51 Labels: ready-for-human, wayfinder:task

Comments

local — 2026-10-21T04:10:00.000Z

按 /wayfinder 接手。路径指向的 cockpit-real-data-wayfinding/52 是已 resolved 的后端优先级票,按标题选择本 effort 票。

复跑三个离线回归全部通过。实测核验设施/井关系契约:map-snapshot 设备侧 networkId 0/8、点位 0/7;monitoring-points/{code} 的 devices[] 无 networkId;device-boundary 只给 facilities+devices 两份扁平清单、无关系边;cockpit 免鉴权 Swagger 无设施关系端点;manhole/device/rel/list 需 401。因此「真实关联优先」分支在真实数据下永不触发,运行时按已批准的邻近示意降级。

归类:外部契约依赖(补齐需后端新增端点)+ 需人工测试(现场视觉验收)。两点均写入正文并给出清单。

Answer

代码与离线回归完成,核验部分已闭环;剩余两件不由 AI 代劳:① 维护者在正式入口目检设备图标/槽位/内部详情;② 后端补齐「设备→设施」关系契约后,真实关联分支才会在真实数据上生效(当前按已批准的邻近示意降级,不伪报完整覆盖)。