Type: implementation Status: resolved Blocked by: 42, 43, 44, 46 Labels: ready-for-agent
按规格 17 处理同一监测点下设备坐标相同或极近的呈现和拾取。静止态显示无设备身份的重叠聚合符号:最高优先级可见设备状态色/形加 K 徽标;hover 瞬态预览环/扇形,click 粘性展开为屏幕层分离,不改变任何真实坐标。展开后普通 pick 走独立设备拾取和票 15 选中反应;禁止 drillPick 和把视觉分离写回空间数据。
map.overlap.maxFan(默认 10)控制。deviceCode,设备点优先于监测点拾取。data-map-overlap-state 和 data-map-overlap-count,不破坏既有设备/面板断言字段。已完成并关闭。 领域断言 18/18、变异 6/6 全部打红、真机走查 16/16(连跑两次稳定),
全量零依赖闸门回归绿(t04/t28 两处既有红与本票无关,均为并发/环境问题)。
domain/overlapDevices.js(新):重叠设备聚合纯函数。groupOverlappingDevices()(同点位近距分组,
K=可逐台绘制数、N=快照关联总数);aggregateMarker()(聚合符号无 deviceCode);fanLayout()
(屏幕圆环展开,不改经纬度);transitionOverlapState()(hover 预览 / click 粘性 / 三条件收起);
resolveOverlapPick()(设备优先、聚合兜底);shouldCollapseOverlap()。domain/deviceLayer.js 复用:K 只认 placement === 'drawn'(坐标有效且当前模式可见),
no-location/terrain-pending/hidden 等不混入 K(票 42/44 既有互斥分类的延伸)。services/cesiumEngine.js:syncAssociatedDevices(devices, colorOf, imageOf, overlapGroups) 重建时
对每组画无身份聚合实体(properties.overlapAggregate=true + K 徽标 label)+ 保持逐台实体
(properties.overlapGroup 标记归属,show:false 折叠隐藏);setOverlapPresentation({groupKey, state, preview, offsets})
用 pixelOffset 做屏幕层分离(真实 position 不动);readOverlapTargets() 只读窗口坐标供走查;
pickDeviceMarkerAt() 先普通 scene.pick(认 deviceCode / overlapAggregate),落空时用投影近邻补偿。services/mapService.js:syncAssociatedDevices(drawn, { maxFan }) 计算 overlapGroups;
K/N 状态机(overlapPreviewGroup / overlapExpandedGroup / overlapState / overlapCountValue);
expandOverlap / collapseOverlap / toggleOverlap(按 groupKey,同点位多组互不干扰);
pickDeviceOrPointAt 展开子设备先收起环再走票 43 原有选中/详情;空白/返回点位统一收起;
nudgeOverlap / clearOverlapNudge(面板 hover 弱提示,不摊开);DEV 把手 getOverlapState /
getOverlapTargets / toggleOverlap / collapseOverlap / nudgeOverlap。stores/deviceLayerStore.js:overlap 摘要(k/n/maxFan/groups/active/degraded)随 syncForSelection
计算;nudgeOverlapRow / clearOverlapNudge 经 store 转发(组件不直连 mapService,维护票 10 F4)。components/PointDetailCard.vue:清单头部显示「聚合呈现 K 台(降级时补本屏/其余见清单)」;
面板 hover 聚合行只弱提示、click 才经 store 选中展开。services/cockpitConfig.js + config.example.json:map.overlap.maxFan 部署配置(默认 10,
非正整数退回 10 并记 issue)。mocks/contractMocks.js:device-layer-overlap 受控样例(两台设备自身坐标相同、身份各自保留,
EQ-001 ALARM + EQ-002 NORMAL,覆盖 K=2 正常重叠与预警模式过滤);
追加 device-layer-overlap-degraded 样例(11 台设备同坐标、状态混合 3 ALARM / 3 WARNING / 5 NORMAL,
K=11 > maxFan 10 ⇒ 降级形态「聚合呈现 11 台(本屏显示 10 台 / 其余见清单)」,真机验证通过)。MP-001 城南测试监测点 = K=2 正常重叠;· MP-002 太常测试监测点 = K=11 降级。
两份样例由 overlapPointDetail() / degradedOverlapPointDetail() 唯一实现,主场景与专用场景共用
(避免同一份样例登记两处而漂移)。其余点位仍走默认现网边界(设备 UNVERIFIED_COORDINATE/renderable=false)。mocks/index.js:人工测试通道 ?scenario=xxx(Console 里设全局变量刷新即丢,
地址栏才是人工测试稳定入口;两者并存时 URL 优先)。verify/t45-overlap-devices.mjs(18/18)+ 变异 6/6 全打红 +
verify/t45-overlap-walkthrough.mjs(16/16,含 W15 预警模式状态过滤、W14 四既有字段、
W16 无页面错误)+ verify/t45-real-user-path-walkthrough.mjs(7/7,全程真实鼠标点地图标记:
进入系统 → 点开监测点 → 展开设备点 → 逐台拾取;K=2 与 K=11 两场景各跑通)+
verify/t45-main-scene-samples-walkthrough.mjs(5/5,不注入任何场景验证主场景
MP-001=K2 / MP-002=K11 降级直接可见)。verify/t05-adapter.mjs:C1 跟随主场景新样例(MP-002 → 11 台),并补 C1b 钉住 MP-001 的 K=2 样例。domain/filterOptions.js 里 POINT_STATUS_FILTER_KEYS 在 POINT_STATUS_KEYS
之前引用它 —— const 暂时性死区导致模块加载即抛 ReferenceError,驾驶舱根本打不开
(并发会话在途改动引入;已按声明顺序修复)。CockpitShell.vue 把 mockReady 改名 lifecycleReady 时漏改 3 处
mockReady.value,运行期 ReferenceError 打断初始化与筛选跟随(同样是在途改动;已按注释记载的新名补齐)。另修一处只读投影缺陷(本票自己的):点位标记是 CLAMP_TO_GROUND 贴地形渲染,
readPointMarkerTargets() 原先按椭球零高度投影,屏幕坐标与画面标记差出一段地形高度,
真实鼠标按该坐标点打不中(走查抓到)。已改为与渲染同口径(先取地形高度再投影)。
properties 不含 deviceCode/monitoringPointCode,
scene.pick 拾到它只回 overlap action(展开/收起),绝不冒充设备(规格:点到聚合符号不会选中一台不存在的设备)。pixelOffset(屏幕层),实体 position/经纬度
一个字节不动;不写回任何空间语义(CONTEXT.md 人工坐标偏移禁令的边界)。drillPick:展开设备各有屏幕位置,走普通 scene.pick + 投影近邻补偿
(聚合与监测点同屏时 scene.pick 可能只回顶层点位,用 readOverlapTargets 的近邻兜底)。drawn),N=快照关联总数;聚合徽标/图例/清单都按 K,
被聚合/降级/无坐标/待确认/模式隐藏的设备不虚报逐台已上图(票 42 纪律的延伸)。resolveOverlapPick 判 deviceCode 而引擎回 code:展开设备普通拾取永远走不到 device 分支、
恒返回 none(真机走查用同一次 evaluate 铁证抓到:pickDeviceMarker 回 EQ-001 而 pickDeviceOrPoint 回 none)。
修法:判定认 (code || deviceCode),与票 43 resolvePickOrder 同一引擎形状。readOverlapTargets 用 entity.isShowing(渲染态):headless 下 show 改变后 isShowing
要等一帧才同步,导致展开态设备被误滤掉、聚合反而可见 —— 拾取判据反了。改用逻辑 entity.show。preview/sticky 两种呈现。驱动:verify/cdp-driver.mjs(票 44 交付的零依赖 CDP 驱动),document.hidden === false。
真实 CDP 鼠标(move/down/up)+ 仅测试态让锚定浮层 pointer-events:none(既有点选浮层遮挡画布,
与票 45 产品无关,走查声明)。
deviceCode、pixelOffset 屏幕分离、聚合隐藏;picked=EQ-001、panel=equipment);data-map-picked / data-map-device-picked / data-map-panel-selection /
data-map-device-hovered 字段保留;W15:无页面级报错。走查环境记录:真实鼠标空白点击需落在 canvas 区域(面板覆盖画布时 pointer 不达宿主)——
走查据此选用 (700,800) 并在断言中显式核验 elementFromPoint 与 pointer 到达计数。
deviceLegend()(票 44 移交)去留。零依赖闸门 36 道全绿(含本票新增 t45;t41 的 E4 注释误伤已调整 —— 注释不含 drillPick 字样)。
两处红与本票无关:① t28-fill-container.mjs 需 puppeteer(模块不在本机);
② t04-config.mjs 指向 services/cockpitApi.js(并发会话正在改)。
按 AGENTS.md:本会话未跑 build;yarn dev 未由我启动(8000 端口已有服务在跑)。
浏览器仅用于本次走查(维护者授权的提权通道,同票 44)。