# 前端执行票 —— 运行信息指标列表分页(实测 6772 条 / 2.3 MB)与「指标占位」块名纠正 ## Question 维护者 2026-10-19 反馈第 2 条:基础设施「运行信息」面板没有分页,且块标题「指标占位」与实际内容不符(意义不明)。 **实测(2026-10-19,`192.168.110.96:8301` 只读接口)**:`/infrastructure/operating-information` 一次返回 **6772 条指标**(GAS 699/WATER_SUPPLY 2497/DRAINAGE 3576/MANHOLE 0),响应体 **2.3 MB**;前端 `operationPanel` 用 `listBlock('指标占位', metrics)` 全量直渲。这是一个行业一屏就画几千条卡片——比监测点台账严重得多的「无限拉长页面」。 **根因**:票 57 首版规范把它列为「排除项」,依据是代码推断的「单行业指标条数契约有界」;真实数据证伪(见规范修订记录)。同时块标题「指标占位」是占位期遗留词,实际是真实指标列表。 ## Acceptance - 运行信息指标列表接入统一分页:每页 ≤10 条、页码直达、输入框跳页、一页不画控件(复用批次一 `PagerNav.vue`)。 - **块标题如实**:「指标占位」改为反映真实语义的说法(如「运行指标」),不再用占位期措辞;若维护者另有命名偏好,在票面记录裁定后落地。 - 先按当前行业聚合的指标集合分页(`selectedIndustry` 回显块),**不在本票发明跨行业合并口径**。 - 面板如实说明数据来源与口径(指标来自设施实体适配器、`pointCodes` 是设施编码——票 49/50 既有裁定,不重开)。 - 换行业/片区筛选时页码复位;数据刷新不复位、越界夹回。 - 闸门 + 变异打红;按 AGENTS.md 跳过 build/dev/浏览器验证。 ## Context - 代码:`domain/infrastructurePanels.js` 的 `operationPanel`(`listBlock('指标占位', …)`)、`services/infrastructureApi.js`(`/infrastructure/operating-information`)。 - 既有裁定:[票 49](../cockpit-point-locate-and-device-link/issues/49-49-operating-information-pointcodes.md)(`pointCodes` 是设施编码)、[票 50](../cockpit-real-data-wayfinding/issues/50-operation-locate-buttons-removal.md)(撤定位按钮)、[票 51](../cockpit-real-data-wayfinding/issues/51-operation-industry-block-selection.md)(按回显 `selectedIndustry` 定位块)。 - 规范:[全局分页规范](../specs/2026-10-18-global-list-pagination.md) 盘点表「基础设施 · 运行信息指标列表」。 ## Related spec [`../specs/2026-10-18-global-list-pagination.md`](../specs/2026-10-18-global-list-pagination.md) ## 进度 2026-10-19 认领并实施完毕(闸门 + 变异闭环)。**已提交并推送**:提交 `0117a5e`(`4d80d30..0117a5e` → `origin/master`,远端已核实 == HEAD)。 > 入库过程如实记:期间并行会话把本票的 `domain/pagination.js`(四个寻址/复位函数)、`PagerNav.vue` 与规范的「裁定第 3 条」卷进了它的提交 `18263a6`,而 `infrastructurePanels.js` 的块标题在 `origin/master` 上仍是 `指标占位`、`t56` 里没有 `sourceNote` 条目——远端一度处于**半入库状态**(票 64 闸门当时在远端跑不出绿)。本票的提交把剩下的部分补齐,使远端回到自洽。 - [x] 领域层:块标题 `指标占位` → **`运行指标`**;`listBlock` 新增可选 `paginate` / `pageScope` 声明(不传时块形状一字不改,既有调用零影响)。 - [x] 领域层:新增 `sourceNote`(数据来源与口径),并入票 56 的折叠摘要表(`data-panel-source-note` 断言面)。 - [x] 单源:`domain/pagination.js` 增加 `listPageKey` / `readListPage` / `writeListPage` / `resetListPages`(页码寻址与复位也只有一份)。 - [x] 渲染层:`PanelBlocks.vue` 的 list 分支接共享 `PagerNav.vue`(页码直达 + 跳页 + 一页不画控件),行数由 `windowOf(block)` 给;仅对 domain 声明的块切窗口。 - [x] 外壳:`panelViewOf('operation')` 传 `{ scope }` 给 domain 算 `pageScope`(换片区复位判据)。 - [x] **顺带修的真实缺陷**(见 Answer 第 3 条):指标行 `key` 在真实载荷里整块碰撞(燃气 699 条同 `metricCode`)。 - [x] 闸门 [t64](../verify/t64-operation-metrics-pagination.mjs) **61/61** + 变异 [t64-mutations](../verify/t64-mutations.mjs) **17/17** 打红按字节还原。 - [x] 既有闸门回归:t59 37/37、t56 33/33(+ 变异 9/9)、t51 20/20(+ 3/3)、t50 15/15(+ 4/4)、t44 109/109(+ 6/6)、t46(+ 12/12)、t38/t39/t40/t27/t54/t55/t20 全绿。 - [x] 规范一致性补漏:`specs/2026-10-18-global-list-pagination.md` 第 13 行的排除清单**仍写着「运行信息指标占位」**,与同文件 2026-10-19 修订记录自相矛盾 → 已删该词条并把它补进「前端集合分页」清单。 - [ ] 真实浏览器走查:按 AGENTS.md 未自动执行,待维护者授权(同票 39/48/50/51 收口方式)。 - [x] **mock 样例扩面问题已裁定(2026-10-19 维护者)**:mock 每个行业块只有 2–3 条指标(实测:GAS/WATER_SUPPLY 3、DRAINAGE 2),`pageCount` 恒为 1 ⇒ 默认 mock 环境下整块 pager 不出现(符合条文 4)。曾问是否把样例补到 >10 条/块用于当场演示——**裁定:可以补但没有意义,验收与走查一律以真实数据为准**。已升格为本图 Notes 的常设偏好 + 规范「维护者裁定」第 3 条(批次二~五同循,不再各自来问)。多页行为维持由闸门用真实载荷证明(t64 V 组 70 页逐页对账);真实分页观感归[票 18](18-frontend-real-integration-gate.md) 的真实联调窗口。 Status: resolved Assignees: agent Type: task Blocked by: #59 Labels: wayfinder:task ## Comments 2026-10-19(实施者):块标题取 **`运行指标`** —— 票面 Acceptance 给的示例词,与面板名「运行信息」、空态文案「当前行业没有运行指标」、领域函数 `toOperatingMetric` 同一套词,不新造第四种说法。维护者若另有偏好,改 `infrastructurePanels.js` 里那一处字面量即可(标题是单源,闸门 D1/S4 会跟着判红提示)。 2026-10-19(实施者):既有闸门两处按成例处理,均与本票判据语义无关—— ① [t56](../verify/t56-panel-summary-disclosure.mjs) 的 `EXPECTED` 表补 `sourceNote` 条目:**是它的 C 组双向普查自己判红的**(domain 新增说明字段不进折叠表=漏网隐形),不是本票绕过守卫;补完后 33/33 + 变异 9/9 全绿。 ② [t50-mutations](../verify/t50-mutations.mjs) M4 的变异锚点未命中(BAD):票 50 落盘后该行末句又被未提交改动改成「(地下管线详情视图)」,脚本里留的是「(重点对象局部增强)」——**锚点过期,不是缺陷复活**;本票未动过 `locateNote`(`git diff` 零交集已核)。仅重新对准锚点,判据(退回旧说法必须红)一字未动,改后 4/4。 ## Answer **验收逐条对账**(判据与证据都在 [t64 闸门](../verify/t64-operation-metrics-pagination.mjs),61 条断言,都不启浏览器、不联网): 1. **接入统一分页** ✅ 复用批次一的 `domain/pagination.js` + `PagerNav.vue`,本票**零新翻页算术**:真实燃气 699 条 → 首屏只画 10 张卡、计数行「第 1/70 页 · 共 699 条」;页码直达 + 输入框跳页 + 到边 disabled 保占位 + 一页不画控件(S1/S2/S3/S7)。V12 是**逐页全扫**——70 页每一页画出来的 key/标题/读数必须等于领域行的对应切片(内容级判据;只数卡片数抓不到「页码显示对、画错行」)。 2. **块标题如实** ✅ `运行指标`;「指标占位」在视图产物与真实渲染的 DOM 里**彻底不存在**(D1/S4,变异 M2 退回旧词当场转红)。 3. **顺带修掉一个真实缺陷(分页把它从理论问题变成每帧都碰的问题)** 真实载荷里**燃气 699 条指标全是同一个 `metricCode`**(`gas_pipe_network_length`「太常片区燃气长度」,逐设施一条),旧行键 `${行业}|${指标码}` 于是**整块碰撞**:699 张卡共用一个 `:key`,而清单卡是 keyed v-for → 节点身份不存在。实测旧写法翻页内容仍正确(靠下标兜底),但这是运气不是保证;已给键加序号后缀(D7 判 699/699 唯一;变异 M4 退回旧键当场转红)。**没有**重排行序(D6 逐条对后端返回序,票 10/11「前端不重排」立场不变)。 4. **按当前行业聚合、不发明合并口径** ✅ 分页的集合就是票 51 定位出的 `active` 块那一条 `metrics`,领域层仍交出**整块 699 行**(D5)——分页只切展示窗口,不裁数据、不改口径。 5. **如实说明来源与口径** ✅ 新增 `sourceNote`:「运行指标由后端按设施实体逐条生成(水厂/泵站/管网/排水设施四类适配器),一条指标对应一个设施;当前行业取后端回显,不跨行业合并」。走票 56 既有折叠摘要(`v-show`,文本在 DOM 里不丢,S5)。票 49/50 裁定不重开:行 `points` 恒空、`locate` 恒空(D13)。 6. **复位与保持** ✅ 换行业/换片区 → 页码回第 1 页(V4/V5);定时刷新 → 页码保持(V3);跳页超界 → 由 `pagedRows` 夹回最后一页、不画空表(V8/R5)。 **这一条返过工,教训留在这里**:第一版把筛选条件编进页码归属键,宣称「复位由构造成立、不写 watch」。对抗式自查时拿规范条文 6 逐字核对,发现它**切走再切回会读到旧槽位停在第 3 页**(「切回燃气」同样是一次条件变化),违反条文 6;且与票 46/59「换设备显式清页码」的既有成例分叉。改成显式清槽(`resetListPages`,只清点名的块),并补 V11a/b/c 三条断言钉住「切走—切回也回第 1 页」;变异 M16 成对复现第一版设计(条件进键 **且** 无清槽),只有 V11c 判得出——V4/V5/V3 全绿。**注**:只改「进键」而保留 watch 是**等价变异**(实测假绿,行为与正确版一致),故不列为有牙判据。 7. **排除项没被顺手接入** ✅ 管理信息片区×行业明细(实测 9 行)不声明、不画控件、9 行照旧全画(N1)。**N8 才是这条的牙**:另造一个「12 行但未声明分页」的块,必须仍全量画出零控件——N1 的 9 行本来就 ≤10,抓不住「渲染层不分声明一律切窗口」(变异 M1 对应 N8)。`listBlock` 不传 `options` 时块形状一字不改(N2/N3)。 8. **闸门 + 变异打红** ✅ t64 61/61、t64-mutations 17/17 全部被对应断言抓住并按字节还原。 **验证层级如实说明**:判据覆盖到「真实载荷 → 领域层 → 共享渲染层(SSR + Vue 自定义渲染器真实 patch)」,含逐页内容对账与交互驱动;**未**在真实浏览器里走查(AGENTS.md 项目规则,且本轮未获授权),因此视觉排布(pager 在面板栏宽内的换行/贴边)未取证实物证据。按项目规则已跳过 build/dev/preview 验证。 **落盘资产**:闸门 [verify/t64-operation-metrics-pagination.mjs](../verify/t64-operation-metrics-pagination.mjs)、变异 [verify/t64-mutations.mjs](../verify/t64-mutations.mjs);诊断探针(含 70 页全扫与「重复 key 会不会画错内容」的实测)留档在 [verify/artifacts/t64/](../verify/artifacts/t64/);载荷沿用票 51 的 `verify/artifacts/t51/`(未新取数)。 **改动文件与入库归属(提交 `0117a5e`,整文件范围=维护者选定)**: - 本票提交所含:`domain/infrastructurePanels.js`(标题 / 分页声明 / 行键 / `sourceNote` / `pageScope`)、`domain/panelBlocks.js`(`listBlock` 可选第 4 参)、`components/PanelBlocks.vue`(分页状态 + 条件变化清槽 + 共享控件接线)、`CockpitShell.vue`(把当前片区传给运行信息面板)、`services/infrastructureApi.js`(一行注释与既成事实对齐);`.scratch` 侧票面、[map](../map.md)、新票 [73](issues/73-10.md)、`verify/t64-operation-metrics-pagination.mjs` / `t64-mutations.mjs` / `t56-panel-summary-disclosure.mjs`(补 `sourceNote` 条目)/ `artifacts/t51/`(本票闸门读它,随闸门入库,沿用本仓 `verify/artifacts` 已有 410 文件的先例)/ `artifacts/t64/` 探针。 - 已由并行提交 `18263a6` 入库(非本票提交):`domain/pagination.js`(含本票追加的四个函数)、`components/PagerNav.vue`、[规范](../specs/2026-10-18-global-list-pagination.md)。 - **两处连贯性依赖是被迫同批进来的,不是本票的功能范围**:`components/PipeColorLegend.vue`(票 48 的 hunks 在 `CockpitShell.vue` 里 import 它,不带上则推送树运行时断裂——扫描器实测:HEAD 的 `CockpitShell.vue` 并不引用它,引用只在工作树版里)、`mocks/contractMocks.js`(票 49/50/51/08 已收口的 mock 侧,是 t64 M 组的前提——模拟推送树实测:不带则 **M3 判红**,60/61)。该文件不含任何 open 票(60–73)的标记。 - **未入库、留给后续**:`verify/t50-mutations.mjs`(我改过它的 M4 锚点,但它调用的 `t50-operation-locate-buttons-removal.mjs` 在 HEAD 里不存在——单独提交变异器会得到跑不起来的半成品,故退出本次暂存);`verify/t50-operation-locate-buttons-removal.mjs`、`t51-operation-industry-block-selection.mjs` 等票 49/50/51 的闸门脚本仍未跟踪。 - 提交后在模拟推送树(worktree=HEAD + 本批文件)复跑闸门面:t64 61/61、t59、t44、t46、t20、t38 全绿;纯 HEAD 基线对照证明 t39/t40/t50/t17/t18/t05 的红与本次提交无关(前三个的闸门脚本在 HEAD 里就不存在,后三个是 `MANAGEMENT_REGION_GAP`/`REGION_MAP_GAP` 的 HEAD 级既有红)。 - 其余并行在制品(`MapCanvas.vue`/`mapService.js`/`monitoringPanels.js`/`pointStatus.js`/`tokens.css`/`tools/city-massing/*`/`CONTEXT.md` 等 20+ 文件)**未被本次提交携带**(`git show --name-only` 已核)。