What to build: 在总体概览一级模式下同时展示态势总览、基础设施、运行监测、预警设置四个二级面板,形成城市生命线整体态势摘要。
Blocked by: 17, 18, 19
Status: resolved Labels: ready-for-agent
逻辑闸门 63/63 · 变异测试 14/14 · 真机走查逐组通过(DSH 浏览器驱动)。
四块面板接三个概览端点(/overview/infrastructure、/overview/monitoring、
/overview/warning-settings)+ 借票 17 的 /infrastructure/base-archives 取区域分布;
三块各自成败(一块端点坏了其余照常画出真实内容),态势总览不自己取数、
由另外三块合成,所以「预警总数」在态势总览与预警设置里按构造是同一个数。
domain/overviewPanels.js(新):四块的契约适配 + 视图计划(纯函数)。services/overviewApi.js(新):四个端点(含借用的 base-archives)的唯一出口。stores/overviewStore.js(新):四分区 + 态势总览的合成 + 两条联动出口。mocks/contractMocks.js:三个 /overview/* 端点(按请求真的回显/过滤)。components/PanelBlocks.vue:新增通用 panel-action 转发与可点 KPI/分布行
(渲染层仍不认识 panelId,票 18 解除的耦合没长回来)。domain/panelViews.js + CockpitShell.vue:注册并接进共享接缝(16 块面板至此全部接上真实视图)。verify/t20-overview-panels.mjs(新,63 项)+ verify/t20-mutations.mjs(新,14 条变异)。1. 预警与报警两族都画、不做切换,且态势总览与预警设置共用一次取数。**
/overview/warning-settings 一次响应就同时给 warning 与 alarm(逐类读过响应类)。
做切换等于把已经拿到的数据藏起来,还会把概览与预警处置的 eventStore.mode 耦上。
两处读的是同一个对象引用(D2b 断言),所以数字不可能对不上。
2. 「近 7 日趋势」必须真的声明窗口,否则只是一句空话。
后端趋势桶跟随声明窗口过滤(CockpitOverviewWarningSettingsService.resolveWindow);
不声明时维持 CURRENT_BASELINE(无界)。本票固定声明 LAST_7_DAYS,界面并回显窗口类型。
3. 「区域分布」不在概览端点上 —— 借兄弟端点,但只借纯适配层。
/overview/infrastructure 只有 Totals + Industries + Excluded(无区域字段)。
区域数据真实存在于票 17 的 base-archives,故复用其纯适配函数 toBaseArchives();
只引适配层、不引块构造器(那才是票 18 抽出 panelBlocks.js 要避免的耦合)。
它同时带来里程与规模两个读数,一并呈现。
4. 「故障统计」后端没有这个桶 —— 不发明,如实标缺口(维护者 2026-09-29 裁定)。
Counts.Status 的真实四桶是 online/offline/stale/unknownOrMissing(服务第 175-182 行
只认 ONLINE/OFFLINE/STALE)。维护者指出「数据过期未必是故障,可能只是网络波动」,
故不合成一个"故障"数,四桶按本义呈现(滞后 ≠ 故障),缺口写成 MONITORING_FAULT_GAP 印在面板上。
5. 「联动地图」在概览数据上做不到 —— 改走两条真实存在的路。
三个概览端点都不含点位编码或坐标(逐类读过),票 17 的 mapLocate 接缝没有可绑对象。
故联动走:① 指标读数 → 切到预警处置模式落到真实事件列表(那里的事件带 deviceCode,
再由票 13/14 既有链路跳点位);② 行业构成行 → 写全局 filterStore.setIndustry
(真的同时驱动一张图与各面板)。不伪造一次地图定位。
6. 分母为 0 不是 0% —— 且这条判据只有一份实现。
票 18 在在线率上用 M3/M14 两条变异测试守过这一族;本票的在线率与处置率都要它。
故把 handlingRateView()/handlingRateHint() 从票 19 的模块导出供两处共用,
并给 toHandlingEfficiency() 补带 handlingState("分母为 0"与"真的是 0%"分得开)。
7. ⚠️ 真机走查逮到真缺陷:两块面板的读数全是 —,而逻辑闸门 59/59 全绿。
monitoringSummaryPanel 与 alertSettingsPanel 以为 data 是 {monitoring}/{warningSettings}
包装对象,而外壳传的是裸 section.data。测试喂的正是那个错误的包装形状 ——
测试与实现犯了同一个错,所以闸门看不见。
已修,并补三条护栏:C3/C4(按真实形状断言读数是数字)、D8(经 panelView() 端到端逐块读数字)、
F6c(钉住外壳逐块的数据源分派)。
教训:手喂 data 的单元断言证明不了"外壳喂进来的形状是对的"——必须有一条走外壳真实入口的断言。
8. 变异测试又逮到两条"守卫比它要守的东西宽/窄"(本仓第 N 次)。
① F6b 第一版只查 linkToMode/linkToIndustry 在文件里出现过 ——
而它们在 handlePanelAction 的定义里当然出现,于是删掉 @panel-action 绑定(联动出口实际断掉)
根本测不出来(M13 全绿)→ 改为断言两处模板绑定都在。
② F3 的裸字段词表只列了本票用到的几个,比 t05 的 D1 窄 → 改为与 D1 同宽。
9. 工单状态字典按后端权威枚举对齐到 0–7(维护者裁定),并删除冗余副本。
后端 CockpitWorkOrderStateDictionary 的类注释原文:「与运行时 WorkOrderStatusEnum(0–7)对齐…
终态为 5、7,延期中是处理旁路」。前端旧表是 1–7 且把「已结案」标在码 6 上 → 每态错位一格。
已对齐(含 WORK_ORDER_CLOSED_CODE 6→5、主线 1→6 改为 0→5、新增 BYPASS 动作),
并删掉 mock 里那份重复字典(改为从唯一源派生)。跨票影响见下。
逻辑闸门 63/63(verify/t20-overview-panels.mjs,六段):
node .scratch/cockpit-shell-panel-layout/verify/t20-overview-panels.mjs
state、0–7 共 8 个码全铺、窗口回显。panelView() 端到端逐块读数字;行业筛选真的重算且不重取不可筛的块;
窗口真的声明;空 ≠ 失败。hasPanelView 与三态措辞、F6b 断言两处模板绑定、F6c 钉住逐块数据源。对抗式自查(变异测试,14 条全部以断言失败打红闸门):
node .scratch/cockpit-shell-panel-layout/verify/t20-mutations.mjs
M1 凭空造「故障」桶 → B2b;M2 不声明故障缺口 → C3c;M3 分母为 0 直画 0% → C1d; M4 状态分布退回 1–7 → B3c;M5 态势总览改读拷贝 → D2b;M6 区域失败遮整块 → D3; M7 指标联动变空操作 → E1;M8 行业联动不写筛选 → E2;M9 行业筛选不重取 → D6; M10 渲染层长出 panelId → F5;M11 domain 反向 import service → F1; M12 store 写后端裸字段 → F3;M13 外壳不接联动动作 → F6b;M14 不声明窗口 → D7。 14/14 被抓住,还原后复跑全绿。
变异脚本自身的两处坑(都已修,记下来免得下次再踩):
① 子进程输出用管道会被本机沙箱以 EPERM 拒(Windows confined mode 不允许开命名管道)→
改成把 stdout/stderr 写进临时文件描述符;
② 本仓 .vue 是 CRLF,而变异源文本按 \n 写 → 出现"变异源文本未找到"的假失败 → 按目标文件换行风格归一。
真机走查(已执行:2026-09-29,逐组通过)
本机 @puppeteer/browsers 是空目录(票 01 记录的既有环境问题,非本票引入),
故沿用票 36 的办法:用 DSH 自带浏览器真实驱动同一份页面,逐项跑同一批断言。
| 组 | 验的是什么 | 实测 |
|---|---|---|
| A | 四块真面板、四块 success、零占位 |
4 块面板 / 0 占位 |
| A | 态势总览 KPI 从 DOM 读 | 设施底数 5处 · 监测规模 9台 · 智能设备 9台 · 监测点 7个 · 在线率 75.0% · 当前预警 8条 · 当前报警 9条 · 处置率 62.5% |
| A | 两条近 7 日趋势 | 近 7 日预警趋势 / 近 7 日报警趋势(14 个趋势点) |
| A | 基础设施含行业构成与区域分布 | 设施 5处 · 里程 12.4km · 规模 中型 · 行业 3 个 · 区域 CN3/CB1/未知1 |
| A | 运行监测四态桶 + 故障缺口印在界面上 | 在线 6台 / 离线 1台 / 滞后 1台 / 状态未知 1台 + 缺口说明 |
| A | 预警设置两族 + 0–7 共 8 个状态码 | 预警 8条/报警 9条;状态分布含延期中 1(新状态真的画出来了) |
| A | 零后端代号泄漏 | 两栏可见文本零 GAS/CURRENT_BASELINE/LAST_7_DAYS/medium 等 |
| B | 行业行 → 全局筛选 + 真的重算 | 筛选 all → gas;在线 6→3台、智能设备 9→4台、监测点 7→3个、正式行业范围=燃气 |
| B | 不可筛的块不假装生效 | 基础设施设施总数 5处 → 5处(该端点不收行业入参) |
| C | 指标读数 → 切预警处置模式 | 点「当前预警」→ 一级模式 = 预警处置,落到真实事件列表 |
| D | 只坏一块不遮其它 | 监测 failed("数据加载失败"),基础设施 9 行分布 / 预警设置 16 行分布照常画出真实内容 |
| E | 空场景 ≠ 失败、不伪造 0 | 三块 empty("无数据"/该面板当前没有数据);0.0% 未出现 |
证据:verify/walkthrough/t20-overview-panels.png。
按维护者裁定「以后端 WorkOrderStatusEnum(0–7)为唯一真理,删除其他不必要的字典」,
本票改动了三张已关闭票的交付面(详见各票的重开记录):
workOrder.js/workOrderTimeline.js 对齐 0–7;
主线 1→6 改为 0→5;新增 BYPASS(延期中是处理旁路,与已取消同为路径外)。
票 12 原验收「不展示延期」与后端权威枚举直接冲突,已作废并同步改 ADR 0003。
闸门 49 → 52 项(回退语义一字未改)。0.0%(已修,并导出共用判据)。
另外本票发现票 19 从未把新文件补进 t05 的静态守卫面(票 11/17/18 都补过),
实测那两个文件干净后已补入(t05 255 → 270 项)。A8b 断言"总体概览恰好 4 块占位",被本票接真面板后必然假红 ——
这是钉在别人票进度上的断言(票 18 在完全相同处境下已栽过一次并已自修)。
按 Q9=(a) 去魔数化:只断言本模式,其余模式只汇报。map.ui.debug 决定顶栏是否显示诊断读数(票 32),与本次改动无关。总体概览四块面板落地:接三个概览端点 + 借票 17 的档案端点取区域分布, 三块各自成败(一块坏了其余照常画出真实内容),态势总览由另外三块合成 (故与预警设置的数字按构造同源)。
四条边界如实划清,不发明业务:
① 「故障统计」后端没有该桶 —— 四态如实呈现并标缺口,不把「滞后/状态未知」折算成故障
(维护者 2026-09-29 裁定:故障语义复杂,不合成);
② 「区域分布」不在概览端点上 —— 借票 17 的 base-archives 纯适配层,只引适配不引构造器;
③ 「联动地图」在概览数据上做不到(三端点都不含点位编码/坐标)—— 改走两条真实存在的路
(指标→切预警处置模式落到真实事件列表;行业行→写全局筛选真的驱动地图),不伪造定位;
④ 分母为 0 不是 0% —— 在线率与处置率共用同一条判据,不画虚假零值。
票面七条验收全部达成(逐条见正文勾选)。
本票真机走查逮到一个逻辑闸门看不见的真缺陷(两块面板读数全是 —,
而闸门 59/59 全绿 —— 因为测试与实现犯了同一个错,都以为 data 是包装对象),
已修并补了三条护栏(含一条经外壳真实入口的端到端断言)。
跨票改动三张已关闭票(12/19/11)与一张走查脚本(17),均已重开记录、请维护者复核。
已认领(Status: claimed)。本票无 needs-triage 标签,Blocked by: 17, 18, 19
三张前置票均已 resolved,故按闸门规则不经过诊断阶段,直接进入实施;
但票面含多处"不该猜"的地方,故按本仓成例(票 17/18)先做澄清。
读现状时核出的关键事实:本票票面写「0% 未动工」是准确的 ——
前端仓库对 /overview/* 零实现(无 mock、无 service、无 api);
三个端点在后端已存在;且票 24 调研里 situationSummary 那处「趋势窗口不可声明」的缺口
已由后端 BT-3 关闭(warning-settings 现收 range),故「近 7 日趋势」可做。
第一轮:预警/报警并列与共用取数(A)、区域分布读兄弟端点(A)、 故障统计按真实四态不发明(A)、联动走事件列表+全局筛选(B)、真机走查授权(B)、 处置率不加工口径说明(A)、全局筛选只作用于能收它的那块(A)、 补 t05 守卫面(C)、修票 17 假红(A)。
第二轮:维护者补充了故障语义的完整口径(点位四态与设备五态都算异常;
但"数据过期"未必是故障,建议只保留离线统计,语义过复杂则删掉故障统计);
并明确 Q4 的联动语义是"面板中的设备/报警 → 跳到场景中对应点位"。
据此核出:三个概览端点都不含点位编码或坐标,故该语义在本模式数据上无法直接实现 ——
改走"切到预警处置模式落到真实事件列表"(那里有 deviceCode 可再跳点位)。
第三轮:Q10 维护者先答 (c) 后更正为 (b)(一次收口、同步票 12/19 断言);
Q13 裁定以后端 WorkOrderStatusEnum(0–7)为唯一真理并删除冗余字典;
Q14=(a) 延期中画成路径外旁路、口径改中性词;Q16 按此落地。
期间向维护者指出两处硬冲突:「七态」在 0–7 下不成立(是 8 个码)、
ADR 0003「不展示延期」被后端枚举推翻(6 延期中是正式状态)。
实施中自查(变异测试)逮到两条自己的守卫缺陷(F6b 只查词出现过、F3 词表比 t05 窄),
均已修并用变异确认有牙。真机走查又逮到一条真缺陷(两块面板读数全 —,
测试与实现犯同一个错),已修并补三条护栏。逻辑闸门 63/63、变异 14/14、
全量回归 29 个闸门绿(t04-config 与 t28-fill-container 的失败是既有环境问题:
前者因另一张票在 cockpitApi.js 注释里写了 /api/cockpit 而误报,
后者需要 puppeteer 的 @puppeteer/browsers,两者都与本票无关、本票未触碰)。