# 基线卡片 03:报警/工单读模型、设备–监测点回联 + district 片区契约 > 按决策票 [05 真实联调基线与收口证据门槛](../../issues/05-integration-baseline-and-evidence.md) 的固定骨架产出,对应执行票 [12 后端读模型 + district 片区契约](../../issues/12-backend-read-model-district.md)。**状态判定:③ 真实数据联调完成**(2026-10-08/09 部署后复验通过,见 §四;④ 模式整体收口仍待真人验收)。 ## 一、基线 | 项 | 值 | | --- | --- | | 记录时间 | 2026-10-08/09(本地时钟) | | 记录角色 | 后端执行代理(实施 + 编译 + 契约测试 + 部署后复验) | | 联调环境 baseUrl | `http://192.168.110.96:8301`(= 本机,IDE 内运行的 Spring Boot 进程) | | 后端仓库 / 分支 / 提交 | `http://192.168.110.30:3000/shaoy/pipe-ner-server` / `master` / **`818a6d7`**(合并 `ee2e1b6` + `18db910`) | | 运行实例 | PID 15244,启动于 2026-10-09(已加载新构建) | | 后端推送状态 | **已推送**;远端 `master=818a6d7` 与本地一致,工作树干净 | | 前端仓库 / 分支 / 提交 | 本票**不涉及**前端;但契约变更连带影响前端(见 §六) | | 访问控制 | 驾驶舱只读 REST 免鉴权(ADR 0005);实测无凭据 HTTP 200 | | 只读数据源 | 本地联调实例的只读快照;`readOnly: true` | | 目标部署 | `192.168.110.30:8301` **移出本阶段**(不参与状态判定) | ## 二、收口条件五行 | # | 条件 | 状态 | 证据 | 未完成项 | | --- | --- | --- | --- | --- | | ① | 后端提交 / 编译 / 契约测试 | **已完成** | 编译通过;组合测试 **372/372 通过**;`818a6d7` 已推送 `origin/master` | 无 | | ② | 状态筛选与 `MANHOLE` 跨端 | 不在本票范围 | — | 归规格 07 / 执行票 14 | | ③ | `createdAt` 数据时间 | 不在本票范围 | — | 归规格 08 / 执行票 14 | | ④ | real 生命周期 | 不在本票范围 | — | 归规格 09 / 执行票 14 | | ⑤ | 真实环境 / 访问控制 / 数据快照 + 走查 | **已完成(后端契约层)** | 部署后复验 8 项全通过(§四);免鉴权 200 | 前端 real 走查归执行票 14–16;真人验收归决策票 01 | ## 三、本票交付内容 ### 范围 2 —— district 片区契约(六族统一) | 项 | 修订前 | 修订后 | | --- | --- | --- | | 权威来源 | 无(`region` 自由串、适配器写死 `null`) | `equipment_base.district`(0/1/2);**点位经其上挂设备归纳**,不一致/无设备→未分区 | | 响应形态 | `region`(String,恒「未分区」) | `district`(Integer,未分区 `null`)+ `districtName`(「未分区」) | | 筛选入参 | `region`(自由文本、无校验) | `district=0\|1\|2\|UNASSIGNED`;**脏值 400** | | 分布字段 | `regionDistribution` | `districtDistribution` | | `mapFilter` | `region` | `district` + `districtName` + `districtFilter`(`NONE`/`ASSIGNED`/`UNASSIGNED`) | 覆盖六族:地图摘要、运行监测(distribution + situation)、基础设施(base-archives + management-information)、事件多维分析。新增单源 `cockpit/foundation/CockpitDistrict.java`(归一/归纳/入参解析/匹配 + 常量)。 **点位与设施无片区来源这一事实**:`monitor_point` 无 district 列、`PipeNetworkBase` 无该字段、`equipment_point_rel` 实测 **0 行** → 点位实际全部落「未分区」,**如实呈现、不编造**(维护者裁定:不加数据库列)。 ### 范围 3 —— 管理信息删字段 删除 `organizations`、`ownershipDistribution`、`totals.unmaintainedCount`、`totals.organizationCount`、内部类 `Organization`/`Ownership`、`selectedFilters.organizationCode`、`mapFilter.organizationCode(s)`;改为 `districtIndustry[]`(片区 × 行业的设施/设备计数),符合决策票 06「管理信息面板改片区×行业视图」。 ### 范围 1 —— 报警/工单读模型 - 设备维度 `/equipments/{code}/work-orders` 返回该设备**已有全部工单**;每张工单新增**显式**关联标记 `associatedWithCurrentEvent`,响应新增顶层 `unassociatedWorkOrderCount` —— 满足「未关联当前报警的工单明确提示」,调用方不必从 `eventAssociation == null` 反推。 - 报警维度只回实际关联的工单(`alarm_data.work_order_id = work_order.order_id`)。 - 多工单:保留全部明细,不引入「当前工单」规则(维护者裁定)。 ## 四、实测记录(可复制命令与结果) ### 4.1 本地编译与组合契约测试 ```powershell cd E:\pipe-ner-server mvn -o -pl pipe-network-service/zksy-admin -am compile mvn -o -pl pipe-network-service/zksy-admin -am test ` "-Dtest=Cockpit*Test,Business*AdapterTest" "-DfailIfNoTests=false" "-Dsurefire.failIfNoSpecifiedTests=false" ``` 结果:编译通过;`Tests run: 372, Failures: 0, Errors: 0, Skipped: 0`(`BUILD SUCCESS`)。 (注:早期只跑 `Cockpit*Test` 得 311,**漏掉了 `Business*AdapterTest` 一族**;正确组合为 372。) 本票新增/改写的针对性覆盖: - **district 归一**:`unknownDistrictIsRejectedWithBadRequest`(`99`→400)、脏值 `城区B`→400、`7`→未分区(适配器层) - **筛选语义**:`districtFilterMatchesAssignedDistrict`(`0`→`ASSIGNED`)、`districtFilterMatchesNormalizedUnassignedDistrict`(`UNASSIGNED`→只回未分区)、`unassignedDistrictFilterSelectsOnlyUnassignedAndEchoesFilterFlag` - **点位归纳**:多设备片区不一致→未分区;无设备→未分区 - **删字段**:管理信息响应不再含 `organizations`/`ownershipDistribution`/`unmaintained*`,改断言 `districtIndustry[]` - **工单关联标记**:`deviceOrdersFlagUnassociatedWorkOrdersExplicitly`、`eventOrdersAreAllMarkedAssociated` - **报警定位**:`alarmEventResolvesByAlarmIdAndReturnsItsLinkedOrders`、`alarmEventFallsBackToAlarmNoWhenIdMisses`(已做变异检验确认有牙) ### 4.2 部署后真实环境复验(2026-10-08/09,实例 PID 15244) ```powershell $base='http://192.168.110.96:8301/api/cockpit/v1' # 六族端点健康 'map-snapshot?page=1&pageSize=2','monitoring/distribution?page=1&pageSize=2', 'monitoring/situation?page=1&pageSize=2','infrastructure/base-archives', 'infrastructure/management-information','events/multidimensional-analysis?eventFamily=ALARM', 'equipments/21119740/work-orders' | ForEach-Object { Invoke-WebRequest "$base/$_" -UseBasicParsing } # 筛选与脏值 0,1,2,'UNASSIGNED' | ForEach-Object { Invoke-WebRequest "$base/map-snapshot?district=$_" -UseBasicParsing } ``` 结果(8 项全通过): | 复验项 | 实测 | | --- | --- | | 六族端点健康 | 7/7 HTTP 200 | | `district` 字段 | `mapFilter` 含 `district`/`districtName`/`districtFilter`;`region` 已消失 | | 筛选生效 | `0`→4、`1`→2、`2`→1、`UNASSIGNED`→6(合计 7+6=13 == 全量) | | 脏值 400 | `9` / `-1` / `城区B` 全部 400 | | 旧 `region` 被忽略 | `region=城南` → 200 且 `districtFilter=NONE` | | 管理信息删字段 | 顶层无 `organizations`/`ownershipDistribution`;`districtIndustry[]` 7 条(含「未分区」桶) | | 点位归纳 | `equipment_point_rel` 0 行 → 点位全部「未分区」 | | 工单关联标记 | 设备维度逐张 `associated=true`;报警维度按真实 UUID 回 `READY`+1 张 | ### 4.3 一处测量错误与撤回(如实登记) 复验中曾依据「`alarm_data.id` 全部是全零占位值」提交 `905f593`(改按 `alarm_no` 解析)。**该观测错误** —— 是控制台把 32 位十六进制串统一渲染成 `0` 的**显示假象**(`md5(id)` 同样被渲染)。 字符直方图 + base64 复核证明 6 行 `id` 是**互不相同的真实 UUID**(非零字符 30/29/32/29/32/30;`count(DISTINCT id)=6`;base64 解出 `fca8fd6b…`/`8b5c81fc…`,与端点回显一致),且 `events/ALARM/{真UUID}/work-orders` 回 `READY`+1 张。故以 `18db910` 撤回,恢复「先按主键 `getById`、查不到才回退 `alarm_no`」。 **教训**:控制台对长十六进制串的渲染不可信;判「相同/为零」须用 `count(DISTINCT)`、直方图、base64 等不可被渲染扭曲的方式。 ## 五、真人验收 **未执行。** 本卡片不宣称任何人工验收结论。真实设备报警闭环仍按决策票 01 由真人团队执行。 ## 六、未完成项与补齐条件 1. ~~提交与推送~~ —— **已完成**(`818a6d7` → `origin/master`)。 2. ~~部署后复验~~ —— **已完成**(§4.2,8 项全通过)。 3. **前端消费侧(必须同步,已通知 [执行票 15](../../issues/15-frontend-time-dimension-panel.md))**: - `domain/filterOptions.js` 的 `regionQuery`/`hasRegionMapping`/`REGION_MAP_GAP` 与配置 `map.filters.regionMap` 已失效(后端不再接受 `region`)→ 改为下发 `district` 编码。 - `domain/infrastructurePanels.js` 仍读 `organizations`/`ownershipDistribution`/`totals.unmaintainedCount`(约 213–232、430–446 行)与 `MANAGEMENT_REGION_GAP` → 改为消费 `districtIndustry[]`。 - 管理信息 freshness reason 由 `NO_ORGANIZATIONS` 改名 `NO_RELATIONS`(前端未硬编码该字面量,已核实)。 4. **文档**:`docs/cockpit/README.md` 已同步(含新增「片区(district)契约」章节);两个 demo html(`map-snapshot-demo.html`、`monitoring-distribution-demo.html`)仍是 `region:'城区A'` fixtures,未改(离线样例,不阻塞契约)。 5. ~~既有测试失败(非本票引入,需另开票)~~ —— **已修复**(2026-10-09,提交 `4ef2159` 推送 `origin/master`):`WaterSupplyDeviceServiceImplTest`(2) 与 `AlarmClearServiceTest`(1) 为过期断言(根因上游 `7df9a87` 改实现未同步测试),已更新为当前契约(「设备报警」/「监测报警」);`AlarmReviewAttachmentServiceTest`(2) 按维护者裁定整类删除(断言的内容嗅探/伪造扩展名拦截为生产从未实现的策略,且测试环境必然 NPE)。修复后全量 8 模块 **414/414** 通过。本票对这 5 个失败相关文件 **0 处**生产改动(已逐文件核实)。 ## 七、状态判定 **当前状态:③ 真实数据联调完成(2026-10-08/09 达成)。**(④ 模式整体收口仍待真人验收与前端接线。) 依据:编译 + 372/372 组合契约测试通过,且**部署后真实环境复验 8 项全通过** —— `district` 系列字段生效、筛选与脏值 400 语义正确、旧 `region` 被忽略、管理信息三字段已删并改 `districtIndustry[]`、点位片区如实归未分区、工单显式关联标记可用。 **不进入 ④ 的原因**:④ 要求「该模式全部面板 + 地图 + 推送在真人验收下通过」—— 本卡片只覆盖后端契约切片,前端 real 生命周期接线(执行票 14–16)与真人设备报警闭环(决策票 01)尚未发生。 ## 八、关联 - 本图执行票:[12 后端读模型 + district 片区契约](../../issues/12-backend-read-model-district.md) - 复验承载:[17 部署后真实环境复验(后端切片 11–13)](../../issues/17-postdeploy-live-verification.md) - 上游决策:[01 报警—工单闭环读模型与 Gogs 票拆分边界](../../issues/01-backend-slice-ticket-boundary.md)、[05 真实联调基线与收口证据门槛](../../issues/05-integration-baseline-and-evidence.md)、[06 异常统计、工单处置率与管理字段词汇](../../issues/06-cross-mode-business-semantics.md) - 规格:[10 业务语义规格](../../issues/10-business-semantics-spec.md) - 下游:执行票 [13 报警/工单实时同步](../../issues/13-backend-realtime-sync.md) - 上位台账:[票 25 后端契约缺口待办](../../../cockpit-shell-panel-layout/issues/25-backend-contract-gaps.md)、Gogs #63