work-order-read-model-district.md 12 KB

基线卡片 03:报警/工单读模型、设备–监测点回联 + district 片区契约

按决策票 05 真实联调基线与收口证据门槛 的固定骨架产出,对应执行票 12 后端读模型 + district 片区契约。状态判定:③ 真实数据联调完成(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 本地编译与组合契约测试

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)

$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):
    • 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)尚未发生。

八、关联