67-district.md 32 KB

前端执行票 —— 「当前范围」与「行业」筛选生效面审计与补齐(事件族仅预警分析收 district;管线片区由编码前缀推导)

Question

维护者 2026-10-19 反馈第 8 条:上方菜单栏「当前范围」(全部/城南/城北/太常/未分区)没有影响到场景及物体的筛选及部分 UI 中的信息筛选;行业也需一并检查。

核查结论(2026-10-19 读代码 + 只读接口):部分真实缺陷,需按接缝逐条补齐。 已接线与未接线的现状:

行业(较完整,存在 1 处缺口)

  • 已接线:map-snapshot(services/mapApi.js)、基础设施(infrastructureApi)、概览(overviewApi)、监测(monitoringApi)、事件(eventApi/warningResponseApi)、管线图层(pipeNetworkStore.setIndustry)。
  • 缺口:管线几何只吃行业、不吃片区(domain/pipeNetwork.js 第 288 行 districtApplied: false,且注释说明「片区只筛设施点位与统计」)。这是仓内已知并已如实标注的边界,不是静默漏筛。

片区(缺口较多)

  • 已接线:map-snapshot、基础设施、概览、监测分布。
  • 缺口 1(严重):事件族完全没有 district 入参——services/eventApi.js 的 fetchCurrentEvents 无 district;services/warningResponseApi.js 的 rangeParams 也无 district。后端 filters.district 字段存在(实测响应里有),但前端从不传。
  • 缺口 2:CockpitShell.vue 的 watch(scope)(第 1804-1810 行)只重载 infrastructureStore/overviewStore/monitoringStore + refreshMapForFilters,不重载 eventStore——切片区后预警处置四块面板完全不刷新。
  • 缺口 3:管线几何与构件图层不随片区变化(同上 districtApplied:false)。
  • 缺口 4:overviewStore.loadPanels({ scope }) 实际只覆盖部分面板(代码注释「概览只有运行监测那块收行业入参(另两块不收)」),需核实片区是否同样只覆盖一块。

Acceptance

  • 先做完整审计再改:逐面板列出「当前范围/行业」是否进入请求参数、是否进入本地图层筛选,产出对照表写进票面(含后端是否支持该参数)。后端不支持的参数不得前端伪造筛选,也不得静默忽略——要在界面如实说明。
  • 补齐事件族的片区入参(后端 filters.district 已存在);watch(scope) 补 eventStore 重载并回第 1 页。
  • 管线/构件图层的片区能力:若后端几何接口支持 district → 接线;不支持 → 沿用 districtApplied:false 的如实说明并记录后端契约缺口(另开后端票,不在本票伪造)。
  • 审计结论若发现某面板「片区/行业」本就不适用(如纯聚合口径),在票面登记理由,不强行加筛选。
  • 补充闸门:筛选参数进查询串可断言;切范围/行业后受影响的 store 都有重载;未接线的面板有可见说明。
  • 闸门 + 变异打红;按 AGENTS.md 跳过 build/dev/浏览器验证。

Context

  • 代码:CockpitShell.vue(watch(scope)/watch(industry)/refreshMapForFilters)、services/eventApi.js、services/warningResponseApi.js、stores/eventStore.js、domain/pipeNetwork.js(districtApplied)、stores/pipeNetworkStore.js、各 *Api.js。
  • 既有裁定:票 18/20(窨井作为第四行业接线)、票 24(管线几何图层)、票 37(deviceType 全局筛选)。
  • 后端只读接口:http://192.168.110.96:8301/api/cockpit/v1/**,filters.district 字段已在响应中,可作联调依据。

Related spec

../specs/2026-10-18-global-list-pagination.md(本票不涉分页,属同批维护者反馈)

进度

  • 认领(Assignees: agent;阻塞票 #59 已关闭,本票处于 frontier)+ 读全(正文 / 评论(空)/ 标签 wayfinder:task / 父 00 / 阻塞边 #59)
  • 先查后做:逐端点实测代替读代码猜测(见下方对照表;探针脚本与载荷落盘 verify/artifacts/t67/)
  • 审计对照表成稿(本票正文下方),并据它纠正票面两条前提(见 Answer「票面前提的两处纠正」)
  • 实施:预警分析接片区;watch(scope) 补 eventStore 重载并回第 1 页;未接线面板补可见口径说明;管线图层的片区落点上屏
  • 新增闸门 t67-filter-caliber.mjs 77/77 + 变异 t67-mutations.mjs 14/14 打红并按字节还原
  • 实施期间并行在制的票 05–08 落地了概览四端点重做(旧三端点退役)⇒ 复查并更新:概览四块的口径说明改按规格 §1「四端点不收入参」书写(新端点在本机后端实测 404、无实测定性),审计表与结论同步改写,闸门 A7/A8 改钉新导出
  • 回归:t61 39 / t65b 14 / t66 22 / t68 17 / t62 51 / t63 23 / t64 61 / t75 18 / t39 24 / t40 17 / t43 23 / t46 54 / t48 33 / t50 15 / t51 20 / t54 24 / t55 5 / t59 37 / t60 42 / t27 8 / t16 / t45 35 / t13 50 / t14-event-detail 44 / t09 38 全绿;更正后补验管线相关:t24-pipe-layer 18 / t24-pipe-layer-flow 17 / t48-pipe-color-legend 33 / t22-pipeline-rendering 12 全绿
  • 后端契约缺口另立 票 77(本票不伪造筛选)
  • 2026-10-23 维护者更正:管线有片区可分(编码 = 片区+行业+时间编码)⇒ 重开重做 §十:pipeNetwork.js 按编码前缀推导片区、图层真按片区裁剪、说明改口;E 组 18 项重写、变异 14 条(新增前缀错位/推不出对象被静默保留两条)
  • 真实载荷复核(geom-none.json):6762 条前缀推导与 name 片区词 100% 一致零反例;燃气∩太常 586 = 编码 (TC,RQ) 计数 586(三路交叉);现网无 CB/城北
  • 2026-10-23 真机复验失败排查:根因=dev server 转译缓存给浏览器发了旧版 pipeNetworkStore(无 setScope)→ watch(scope) 第 5 步抛错 → 后面的 refreshMapForFilters 永不执行(面板刷了、一张图不刷);处置=touch 模块强制重转译,复验点击后 map-snapshot?...&district=0 且场景计数真的变(§十一)
  • 顺带修 domain/deviceMetricSources.js 的 deviceMetricKind(null) 崩溃(档案分区 EMPTY 时打断设备详情聚合,真机控制台反复出现)
  • 收口(本票 resolved)

Status: resolved Assignees: agent Type: task Blocked by: #59(已关闭) Labels: wayfinder:task

Comments

local — 2026-10-22 开工与调查说明

已查阅范围(一句话结论 / 路径)

  • 本票正文 / 评论(空)/ 标签 wayfinder:task / 父图 00 / 阻塞边 #59(已关闭)⇒ 无 needs-triage,按执行票推进。
  • 代码:CockpitShell.vue(watch(scope)/watch(industry)/refreshMapForFilters/panelViewOf)、domain/{pipeNetwork, panelViews, panelCatalog, filterOptions, eventList, warningResponsePanels, monitoringPanels, infrastructurePanels, overviewPanels}.js、services/{mapApi, infrastructureApi, monitoringApi, overviewApi, eventApi, warningResponseApi, pipeLayerService}.js、stores/{eventStore, infrastructureStore, monitoringStore, overviewStore, pipeNetworkStore, mapStore}.js。
  • 既有裁定:票 12(district 契约)、票 24(几何图层)、票 37(deviceType 全局筛选)、票 56/64(面板口径说明的折叠摘要接缝与 data-* 断言面)、票 61/62(页码条件键纪律)、票 63/65(下属面板与工单端点)。
  • 仓内既有笔记够不够用:不够——票面记的「后端 filters.district 字段存在(实测响应里有)」只对一个端点成立,其余端点收不收这个参数必须逐端点实测才能定;仓内没有这份逐端点台账。因此按 /research 的替代做法做了只读探针实测(不查外网,查的是本仓自己的后端),脚本与原始载荷落盘 verify/artifacts/t67/,结论回填本票。

探针方法与判据(避免"看起来筛了"的假绿)

  • 判据一:非法值 district=99 / industry=NOT_A_REAL_INDUSTRY 是否 400(说明后端真的读并校验该参数)。
  • 判据二:district=0 与 district=1 的响应逐字段比对是否真的不同(排除 requestId/updatedAt/serverUpdatedAt/range.start|end/freshness.ageSeconds 这类随挂钟变的字段)。
  • 只凭"响应里有 filters 字段"会判错:/events/current 的 filters 只有 {mode, level, industry, status},根本没有片区;而 /events/multidimensional-analysis 的 filters 里有 district / districtName 且真的过滤。

收口见 ## Answer。

Answer

已实施并关闭(2026-10-22;2026-10-23 按维护者更正重做管线片区,见 §十)。按 AGENTS.md 跳过 build/dev/preview 与浏览器验证。

一、审计对照表(本票的第一交付物)

判据见上(400 + 逐字段比对)。"前端现状"= 本票开工前的代码实际行为。

面板 / 图层 panelId 数据端点 片区 后端 片区 前端 行业 后端 行业 前端
一张图·监测点 — /map-snapshot ✅ 收且过滤 ✅ 已接(refreshMapForFilters) ✅ ✅
管线 / 构件几何 — /infrastructure/geometry ⚠️ 端点不收,但编码前缀里有片区(片区+行业+时间编码) ✅ 本地按编码前缀裁剪(§十 更正) ❌ 不收(properties 有 industry) ✅ 本地裁剪
基础设施·基础档案 archive /infrastructure/base-archives ✅ ✅ ✅ ✅
基础设施·运行信息 operation /infrastructure/operating-information ❌ 忽略 ❌ ✅ ✅
基础设施·管理信息 management /infrastructure/management-information ✅ ✅ ✅ ✅
基础设施·应急保障 emergency /infrastructure/emergency-support ❌ 忽略 ❌ ✅ ✅
运行监测·监测概览 monitoringOverview /monitoring/overview ❌ 忽略 ❌ ✅ ✅
运行监测·监测分布 monitoringDistribution /monitoring/distribution ✅ ✅ ✅ ✅
运行监测·运行概况 operationOverview /monitoring/situation ❌ 忽略 ❌ ✅ ✅
运行监测·点位台账 monitoringPointLedger 同上(共用一次取数) ✅ ✅ ✅ ✅
预警处置·当前预警 currentEvents /events/current ❌ 忽略 ❌(且旧版整条旁路) ✅ ✅
预警处置·历史分析 historyAnalysis /events/history-analysis ❌ 忽略 ❌ ✅ ✅
预警处置·预警效率 responseEfficiency /events/handling-efficiency ❌ 忽略 ❌ ✅ ✅
预警处置·当前工单列表 块 /work-orders ❌ 忽略 ❌ ❌ 忽略 ❌
预警处置·预警分析 eventAnalysis /events/multidimensional-analysis ✅ 收且过滤 ❌ 本票补上 ✅ ✅
概览·感知设备 perceptionDevices /overview/perception ❌ 不收入参(规格) ❌ ❌ 不收入参(规格) ❌
概览·基础设施 pipeNetwork /overview/pipe-network ❌ 不收入参(规格) ❌ ❌ 不收入参(规格) ❌
概览·预警研判 warningStudy /overview/warning-study ❌ 不收入参(规格) ❌ ❌ 不收入参(规格) ❌
概览·报警处置 alarmDisposal /overview/alarm-disposal ❌ 不收入参(规格) ❌ ❌ 不收入参(规格) ❌

概览四块这一栏的依据强度与别处不同,如实标出来:票 05–08(并行在制)在本票实施期间把概览数据源从旧三端点(/overview/infrastructure、/overview/monitoring、/overview/warning-settings)换成了四个新端点,而这四个新端点在本机后端尚未部署(实测一律 404),没法用"非法值 400 / 0-1 响应不同"那套判据。所以它们的"不收入参"依据是前端实现 + 规格 §1,不是实测。旧三端点时期是实测过的(/overview/infrastructure 任何入参都不变、/overview/monitoring 收行业、/overview/warning-settings 只收窗口)。端点上线后按 verify/artifacts/t67/ 复跑升级证据,登记在票 77。

行业面结论:前端已经接满"后端收"的全部端点(原始审计里"行业较完整、存在 1 处缺口"成立,且那 1 处 = 管线片区,不是行业)。行业缺口只有后端不收的四处,本票不伪造、能上屏的都已说明:/work-orders(实测不认行业 → 工单列表页脚说明)、概览四块(四个端点不收入参 → 四块面板各一句口径说明);另两处(旧 /overview/infrastructure、/overview/warning-settings)随概览重做已退役,其继任者归票 77 复核。

片区面结论:不是前端漏接,而是后端覆盖参差——真收片区的只有 5 个端点(map-snapshot、base-archives、management-information、monitoring-distribution、multidimensional-analysis),其余 7 个事件/监测端点完全不认该参数,概览四块则是端点根本不收入参。

唯一的例外是管线几何:端点也不收片区,但片区信息在设施编码里(片区+行业+时间编码),所以前端能按编码前缀本地裁剪 —— 这条本票起初判错(只看 properties 有没有片区字段),由维护者 2026-10-23 更正,见 §十。

二、票面前提的两处纠正(实测推翻,写进票面以免后人沿错路)

  1. "事件族完全没有 district 入参,后端 filters.district 字段存在" —— 只对预警分析那一个端点成立。/events/current、/events/history-analysis、/events/handling-efficiency 实测不读该参数(非法值照 200、0/1 响应逐字节相同,响应 filters 里也没有片区字段)。所以"补齐事件族片区入参"不可能靠前端补齐,只能:把真收的那一块接上(预警分析),其余如实说明 + 开后端票(票 77)。
  2. "管线/构件图层沿用 districtApplied:false 的如实说明" —— 那句话此前只写在注释里:districtApplied 全仓只有 3 处引用(领域函数、store 的 EMPTY 常量、注释),没有任何界面消费点。也就是说用户从来没看到过这条"如实说明"。本票把它做成真的可见说明(见下)。

三、改动(5 个源文件 + 2 个组件)

文件 改动
domain/filterCaliber.js 新增 筛选生效面的单一措辞来源:SCOPE_FILTER_LABEL/INDUSTRY_FILTER_LABEL、DISTRICT_GAPS(11 块)、INDUSTRY_GAPS(5 处:工单列表 + 概览四块)、districtGap()/industryGap()、PIPE_DISTRICT_NOTE、withFilterCaliber()。文件头把逐端点实测结论写死,便于下次复用
domain/panelViews.js panelView() 出口统一 withFilterCaliber(...) —— 口径说明挂在注册表这一处,面板新增/改名不会漏(也省掉 11 处重复代码)
services/warningResponseApi.js fetchAggregated 增 hooks.acceptsDistrict;只有 fetchEventAnalysis 打开。多窗(90 天)路径的每个窗都带
stores/eventStore.js CONDITION_KEYS 与 conditionSnapshot() 补 scope ⇒ 换片区时三个页码一起回第 1 页,定时刷新不复位
CockpitShell.vue ① watch(scope) 补 eventStore.loadPanels({ mode, scope });② refreshCurrentModePanels() 的预警处置分支补 scope;③ 状态详情里新增 data-pipe-district-note(渲染 PIPE_DISTRICT_NOTE)
domain/eventList.js currentEventsView() 增 gap(当前预警不在 panelViews 注册表里,走自己的视图)
components/EventListPane.vue 渲染 data-panel-gap(与 PanelBlocks 同一个断言钩子)
domain/warningResponsePanels.js 工单列表块的 pageNote 追加行业缺口句(industryGap('workOrderList'))
domain/pipeNetwork.js §十 更正 新增 PIPE_DISTRICT_PREFIX(CN=0 城南 / CB=1 城北 / TC=2 太常)与 pipeDistrictOf();toPipeNetwork() 每条对象带 district;filterPipeNetwork() 吃 filters.scope,返回 districtApplied(全域 false)与 districtUnresolvedCount(编码推不出片区、被排除的可上图对象数)
stores/pipeNetworkStore.js §十 更正 新增 scope 状态与 setScope();filtered 同时吃行业与片区;load() 收 scope

没改:mapStore/monitoringStore/infrastructureStore/overviewStore(片区接线原本就通);任何后端代码;pipeLayerService.js(几何仍是一次全量取回,片区在本地裁剪 —— 与行业同一条纪律)。

四、用户实际看到的两句话(折叠摘要里)

每块"不随当前范围变"的面板(11 块,措辞按端点分化,例如当前预警):

「当前范围」不作用于本面板:后端该端点未提供片区入参(当前事件端点实测下发该参数也不生效),本表始终列出全部片区

一张图的状态详情里(管线/构件,§十 更正后的措辞):

「当前范围」按设施编码规则(片区 + 行业 + 时间编码)作用到管线与构件图层:几何数据本身没有片区字段,片区是从编码前缀推出来的;编码推不出片区的对象(阀门、窨井等少量构件)在按片区查看时不显示,选「未分区」才看得到它们

概览四块(同样在折叠摘要里,凭据是规格而非实测,见上表注):

「当前范围」不作用于本面板:概览四块的数据端点按规格不收入参(不收片区),本面板读数始终为全域

「行业」不作用于本面板:概览四块的数据端点按规格不收入参,本面板读数始终为全部行业

报警效率的工单列表(页脚口径行):

「行业」不作用于本工单列表:后端工单端点未提供行业入参,列表始终列出全部行业的工单(上方分布仍按行业统计)

五、验收自查(对抗式,逐条对 Acceptance)

  1. ✅ 先做完整审计再改,产出对照表(含后端是否支持) —— 见上方第一张表;支撑证据是逐端点实测(不是读代码猜),脚本 probe-district.sh / probe-geometry-and-industry.sh / diff-district.py 与全部原始载荷在 verify/artifacts/t67/,可原样复跑。
  2. ✅ 补齐事件族片区入参(后端已存在的那处) —— 预警分析接上 district(A1/A2/A3 逐片区取值 + 全域不传 + 90 天多窗每窗都带);三个不认该参数的端点一个都不传(A4/F1 反向钉住)。这是票面前提被实测纠正后的诚实版本:能接的接上,接不了的不伪造。
  3. ✅ watch(scope) 补 eventStore 重载并回第 1 页 —— C1(源码接线)+ B2(行为:三个页码都回 1,且请求带新片区);B3 钉住"同条件重取不复位"(条文 6 的反面,别把定时刷新也复位)。
  4. ✅ 管线/构件的片区能力 —— 本票起初判错、已按维护者更正重做(§十):几何 properties 确实没有片区字段(R3 用落盘载荷复算 6766 feature 证实),但设施编码是「片区+行业+时间编码」,片区能推出来 ⇒ 改为本地按编码前缀裁剪(E 组逐条钉住:推导与名称 100% 一致、四个片区取值、推不出片区的对象如实计数、行业×片区正交)。说明同步改口(不再是「不作用于」)。
  5. ✅ 本就不适用的面板登记理由、不强行加筛选 —— 概览四块登记片区 + 行业两条缺口说明,依据强度单独标注(四个新端点在本机后端未部署、实测 404 ⇒ 依据是规格 §1 与前端实现,不是实测;见上表注与 verify/artifacts/t67/overview-endpoints-not-deployed.md)。纯聚合口径的面板(监测分布的状态饼图是全局未筛口径)保持原样,未强加筛选。
  6. ✅ 补充闸门三条 —— ① 参数进查询串可断言:A 组 9 项(含"该带的带上"与"不该带的不许带"两个方向);② 切范围/行业后受影响的 store 都有重载:B 组行为 + C 组外壳接线;③ 未接线的面板有可见说明:D 组 38 项(逐块 + 全注册表正向普查 + 反向普查 + SSR 真的进 DOM)。
  7. ✅ 闸门 + 变异打红 —— t67 77/77;变异 14/14(M1 分析丢 district、M2 当前事件伪造 district、M3 scope 不进条件键、M4 watch 丢 eventStore、M5/M11 删缺口、M6 缺口里塞接口字段名、M7 片区恒不生效、M8 管线说明写回「不作用于」、M13 编码前缀映射错位、M14 推不出片区的对象被静默保留、M9 刷新漏传 scope、M10 删工单行业缺口、M12 注册表绕过口径出口),每条点名打红指定断言并按字节还原。

六、闸门设计里两条值得记住的判据

  • "响应里有 filters 字段"不是证据,非法值 400 才是:/events/current 的 filters 里压根没有片区字段,而票面当初就是被"实测响应里有 district"误导成"后端都支持"。闸门 R 组因此固化了双判据(400 + 逐字段比对),并排除随挂钟变的字段(requestId/updatedAt/serverUpdatedAt/range.start|end,还有 /infrastructure/operating-information 指标的 freshness.ageSeconds)—— 不排除的话,这些端点会被误判成"按片区过滤了"。
  • 口径说明要正向普查,不能只查你改过的面板:D0c 以 implementedPanelIds() 为准,要求每个已实现面板要么有片区缺口、要么属于已接线集合 —— 将来新增面板漏写说明会立刻红。这与票 56 把"说明字段是否有消费点"做成机制是同一条路子。
  • "字段里没有"不等于"数据里没有"(§十 记的第二次同类翻车):我先后两次同一个毛病 —— 一次把"响应里有 filters 字段"当成"后端支持",一次把"properties 里没有片区字段"当成"片区不可得"。两次都是只看一个信号就下结论。E1b 现在用「编码前缀 × name 里的片区词」两路独立信号交叉复核(6762/6762、零反例),E7 再加一路(燃气∩太常 586 与编码 (TC,RQ) 计数相等)—— 判据至少两路,才配叫证据。

七、后端契约缺口(不在本票伪造)

另立 票 77:后端执行票 —— 片区/行业筛选的端点覆盖缺口:事件族三端点补 district、/work-orders 补 industry、概览四新端点上线时定参数面。部署后按 verify/artifacts/t67/ 的同一套探针复跑即可验收。

几何读模型的片区归属已降级为"锦上添花"(§十 更正):前端已能按设施编码前缀推出片区并据此裁剪图层, 所以"几何必须补片区字段"不再是阻塞项;若后端将来直接下发 district/location,前端改 pipeDistrictOf 一处即可。

八、既有红如实留档(与本票 diff 零交集)

闸门 现状 根因(有据)
t56-panel-summary-disclosure 整脚本导入失败 它 import MONITORING_FAULT_GAP/monitoringSummaryPanel,而 domain/overviewPanels.js 在并行在制的概览重构(票 02)里已移除这些导出:git show HEAD: 该文件有,工作树没有;本票未修改该文件
t38-infrastructure-panel-adjustments 整脚本导入失败 同上,缺 infrastructureSummaryPanel
t44-distribution-ranking 整脚本导入失败 同上,缺 alertSettingsPanel
t15-time-district 断言期异常(operationOverviewPanel 的 list 块 rows 为空) 运行概况已按票 62 的追加需求改成读 monitoringOverview.devices(extra),该脚本仍按旧形状直接调面板函数;本票未修改 monitoringPanels.js,且该断言不经过 panelViews
t14-final-walkthrough puppeteer spawn EPERM 浏览器脚本;本机沙箱边界 + AGENTS.md 禁止浏览器验证

按仓内成例不半修这些闸门。

九、下一步

  • 真实环境走查(片区/行业在四模式下的观感、说明文案的折叠摘要是否易读)归票 18 联调窗口。
  • 后端票 77 落地后,前端只需把 filterCaliber.js 里对应条目的措辞删掉、把参数接上(acceptsDistrict 打开),闸门 D 组的正向普查会自动要求更新。
  • 改动未提交:工作树混有大量并行在制品(概览重构、城市体块、场景图标等 20+ 文件),本票 9 个文件需按票 33/36/37 纪律单独裁剪入库。

十、更正(2026-10-23):管线有片区可分,本票 §二/§四 的"不作用于管线"作废

维护者原话:管线编码 network_code 的组成规则就是「片区 + 行业 + 时间编码」 (如 TCRQ202609080001 = 太常·燃气管),另外 location 字段作为位置描述也描述了管线信息 (如那段太常燃气管的 location 是「太常|燃气管线」)。

我错在哪:§二 第 2 条只查了「几何 properties 里有没有片区字段」,没有就下结论"不可本地筛"—— 把字段里没有当成了数据里没有。这跟本票 §六 批评的那条错误(把"响应里有个 filters 字段" 当成"后端支持")是同一类毛病:只看一个信号就下判断。片区信息一直在编码前两位里。

用真实载荷复核(verify/artifacts/t67/geom-none.json,6766 feature)

检验 结果
code 两字母前缀分布 TC 4116、CN 2646、GD 1、YL 3
前缀 × name 里的片区词(两个独立信号) TC → 4116/4116 含「太常」;CN → 2646/2646 含「城南」;零反例
前缀 + 行业字母 TC/CN 各带 RQ(燃气)/WS(供水)/YS(雨水)/GC(管沟),与「片区+行业+时间」规则吻合
三路交叉独立验证 燃气∩太常 = 586,与编码里 (TC,RQ) 计数 586 完全相等
location 字段 几何 properties 里没有这个键(只有 source/sourceId/code/name/industry/typeCode/networkType/networkLevel/pointType/networkId/diameter/remark/sourceCoordinates/coordinateValidation*)⇒ 片区只能靠编码前缀,不靠 location
推不出片区的对象 4 个(GD-001 阀门、YL-YJ-001/002/003 窨井,用的是另一套编码);其中 3 个本来就在「无地图位置」拦下清单(blocked)里,只有 YL-YJ-003 是可上图对象

实现(domain/pipeNetwork.js / stores/pipeNetworkStore.js / CockpitShell.vue)

  • PIPE_DISTRICT_PREFIX = { CN: 0, CB: 1, TC: 2 }(与 filterOptions.DISTRICT_CODES 的后端片区编码同值)+ pipeDistrictOf(code):只认「两位片区字母 + 两位行业字母」的正式形状,认不出回 null(不猜)。
  • toPipeNetwork() 每条 pipe/component/blocked 都带 district; filterPipeNetwork(network, { industry, scope }) 现在真的按片区裁剪,并返回 districtApplied(全域 false/具体片区 true)与 districtUnresolvedCount(被排除的可上图对象数)。
  • 「未分区」的语义=编码推不出片区的那批对象(与后端 district=null 同一读法); 选具体片区时它们被排除并计数 —— 不硬塞进某个片区,也不静默留在结果里。
  • 几何仍是一次全量取回、片区在本地裁剪(与行业同一条纪律:切换即时、不重新发请求)。

两条如实标注

  1. 片区仍是前端推导,不是后端筛选:几何端点实测仍不收 district(district=0/1 响应逐字节相同、非法值 99 也不 400), 所以界面上的措辞改成「按设施编码规则作用到管线图层……片区是从编码前缀推出来的」, 而不是含糊地说"片区已生效"。
  2. CB = 城北 已由维护者 2026-10-23 确认(此前我按拼音推定、标注"可推翻",现已落定): 现网 6766 条几何里一条 CB 都没有 —— 选「城北」时管线为空,是编码里没有、不是没有管线。

票 77 相应调整:几何端点补片区字段从"前端等着用"降级为"锦上添花"——前端已能工作; 若后端将来直接下发 district/location,前端只改 pipeDistrictOf 一处(闸门 E1 会用落盘载荷复核前缀与名称的一致性)。

十一、真机复验失败 → 根因与修复(2026-10-23,维护者实测「按钮不起作用」)

现象:维护者在 http://127.0.0.1:8000/#/cockpit 点「当前范围」按钮,界面毫无变化。

取证(Chrome DevTools 协议只读取证,未改页面):

  1. 点「城南」后 4 个面板确实带上了片区(monitoring/distribution?district=0、 events/multidimensional-analysis?...&district=0、infrastructure/base-archives?district=0、 management-information?district=0)—— 说明点击→store→watch 这一段是通的;
  2. 但一张图一条 map-snapshot 请求都没发;
  3. 控制台里有:

    TypeError: pipeNetworkStore.setScope is not a function
    at CockpitShell.vue:1442  (watcher callback)
    [Vue warn]: Unhandled error during execution of watcher callback
    

根因(两级)

  • 直接原因:我这次给 pipeNetworkStore 新加的 setScope 在浏览器拿到的模块里不存在。 实测证明是 dev server 的转译缓存给旧版:同一 URL 直接取回,return {...} 里没有 setScope; 加 ?t=999999 强制重取就正常。dev server 的 mtime 失效没跟上(Windows 上常见), 硬刷新也救不回来(浏览器刷新不会让 Vite 重新转译),只能 touch 文件或重启 dev server。
  • 放大原因:watch(scope) 里 6 个联动是一串同一个回调,第 5 个 pipeNetworkStore.setScope(next) 一抛错,排在它后面的 refreshMapForFilters 就永远不执行 —— 于是「面板刷了、一张图不刷」, 而界面上没有任何提示(只有控制台 warn)。这正是「筛了但没生效」的最隐蔽形态。

修复与复验

  1. touch 我改过的模块强制 Vite 重新转译(已用 curl 逐文件核对服务端返回的是新版)。
  2. 复验(同一页面、只读取证):
    • 点「城南」→ map-snapshot?page=1&pageSize=2&district=0(第 1 页起全部带 district=0);
    • 一张图状态带真的变了:太常 报警0/预警1/工单0/正常0/离线0 ↔ 全域 报警1/预警1/工单5/正常1/离线2;
    • 基础设施「基础档案」在太常下读数为 设施总数 0 处(设施档案没有片区来源,全部落未分区 —— 票 68 记过的既知事实,不是缺陷)。

顺带修掉一个真实缺陷(domain/deviceMetricSources.js,committed 代码、非本票引入): deviceMetricKind(archive = {}) 的默认值只在未传时生效,而 fetchEquipmentDetailAggregate 在档案分区为 EMPTY 时 显式传 null → archive.type 抛 TypeError,整条设备详情聚合被打断(真机控制台反复出现该异常)。 改为函数内 const source = archive || {} 收口;复验:刷新后控制台 error 归零。

留给运维/开发的一条纪律(写进票面,避免重复踩)

改了 stores/*.js、services/*.js 这类纯 JS 模块后,dev server 可能仍把旧转译结果发给浏览器 (.vue 有 HMR 边界会换,纯 JS 不会)。表现是「新增的 store 方法 is not a function」, 而且浏览器硬刷新也无效。处置:touch 该文件(或重启 dev server),再刷新页面。

观察(不在本票处理):MAP_SUMMARY_PAGE_SIZE = 2(2026-09-18 为演示渐进加载而设,注释写明)。 真实数据下每切一次筛选会连翻几十到上千次 map-snapshot(本次实测一次筛选 40+ 请求)。 演示无碍,真实投用前应调回后端默认 500,否则既是性能问题也像"卡住不动"。