Type: task Status: resolved Label: ready-for-agent Blocked by: 11 Category: backend-execution
已完成并推送(2026-10-08/09)。诊断 + 六项裁定 + 范围 1–4 实施 + 提交推送 + 真实环境复验通过。提交:ee2e1b6(主实施)+ 905f593(被撤回)+ 18db910(撤回)+ 合并 818a6d7 → 已推送 origin/master(89ca989..818a6d7)。验证:组合测试 372/372 通过。基线卡片:报警/工单读模型 + district 片区契约。
本票按其自身交付物 close(原因、证据、下一步均已入正文与基线卡片);真实环境复验记录追加到 票 17(滚动复验票)。
| 复验项 | 实测 | 判定 |
|---|---|---|
| 六族端点健康 | 7/7 全部 HTTP 200(此前 5 端点 500 的故障已由上游修复) | 通过 |
district 字段出现 |
mapFilter 含 district/districtName/districtFilter;region 已消失 |
通过 |
| 筛选生效 | district=0→4、1→2、2→1、UNASSIGNED→6;合计 7+6=13 == 全量 |
通过 |
| 脏值 400 | district=9 / -1 / 城区B 全部 400 |
通过 |
旧 region 被忽略 |
region=城南 → 200 且 districtFilter=NONE(不生效、不报错) |
通过 |
| 管理信息删字段 | 顶层无 organizations/ownershipDistribution;改 districtIndustry[](7 条,含「未分区」桶) |
通过 |
| 点位 district 归纳 | equipment_point_rel 0 行 → 点位全部「未分区」(如实) |
通过 |
| 工单显式关联标记 | 设备维度逐张 associatedWithCurrentEvent=true;报警维度按真实 UUID 回 READY+1 张 |
通过 |
复验中我一度依据「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 张工单,证明原按 id 解析本就是对的。
故以 18db910 撤回该改动:findAlarmByReference 恢复先按主键 getById、查不到时才回退 alarm_no;alarmReference 恢复优先回 id。保留 905f593 中仍正确的部分(lambdaQuery() 链改 list(wrapper) 便于测试 + 新增适配器测试)。
教训:控制台对长十六进制串的渲染不可信;判定「数据是否相同/是否为零」必须用 count(DISTINCT)、字符直方图、base64 等不可被渲染扭曲的方式,不能凭肉眼读控制台。
zksy-system 全量跑有 5 个失败,全部在报警/供水域、与本票无关:
WaterSupplyDeviceServiceImplTest(2)、AlarmClearServiceTest(1)、AlarmReviewAttachmentServiceTest(2)。
根因是上游 7df9a87 把 setAbnormalReason(alarm.getWarningType()) 硬编码为 "设备报警"(删除了 warningType 用法),但测试仍断言旧值 "供水压力超限"。已核实在基点 89ca989 上实现与测试断言本就冲突,且本票 0 处改动这些文件。该失败需另开票修(不在本票范围)。
按维护者六项裁定实施,共 48 个文件改动 + 1 个新增(cockpit/foundation/CockpitDistrict.java 片区口径单源)。六个响应族统一改造:
| 族 | 改动 |
|---|---|
| 地图摘要 | map-snapshot?district=0\|1\|2\|UNASSIGNED;点位/设备 district+districtName;mapFilter 加 districtFilter |
| 运行监测 | monitoring/distribution、monitoring/situation 的 regionDistribution→districtDistribution,marker 双字段 |
| 基础设施 | base-archives 同上;管理信息删字段 organizations/ownershipDistribution/unmaintainedCount/organizationCount,改 districtIndustry[](片区×行业) |
| 事件多维分析 | 维度 REGION/区域→DISTRICT/片区,桶码 0/1/2/UNASSIGNED |
| 工单读模型 | 每张工单新增显式 associatedWithCurrentEvent + 顶层 unassociatedWorkOrderCount |
点位与设施无片区来源(monitor_point 无列、PipeNetworkBase 无字段、equipment_point_rel 实测 0 行)→ 点位按「经其上挂设备归纳」、设施一律未分区,如实呈现,未加数据库列、未用行业/管理单位冒充。
0/1/2/UNASSIGNED,脏值 400。district 取代 region,region 入参不再接受。alarm_data.work_order_id → work_order.order_id(维护者原述 alarm_no = order_no 经实测命中 0 条且两列均不存在,已裁定采用 work_order_id)。| 项 | 值 |
|---|---|
| 仓库 / 分支 / 提交 | http://192.168.110.30:3000/shaoy/pipe-ner-server / master / 89ca989 |
| 远端 | origin/master = 89ca989(与本地一致,工作树干净) |
| 联调环境 | http://192.168.110.96:8301 实测可达,只读接口免鉴权 HTTP 200 |
已有端点与实现(cockpit/workorder/):
| 端点 | 实测 |
|---|---|
GET /equipments/{deviceCode}/work-orders |
真实设备 21119740 回 2 张工单(状态 1 待接单、5 已结案),state=READY |
GET /events/{source}/{code}/work-orders |
可用;ALARM 走 alarm_data.work_order_id,WARNING 走 alarm_warning_rel → alarm_data |
GET /work-orders/{orderNo}/timeline |
可用,状态码经 CockpitWorkOrderStateDictionary 0–7 解析 |
缺口(对照本票「范围 1」逐句):
CockpitWorkOrderSummary.eventAssociation 在无关联时为 null(隐式)。实测两张工单均 eventAssociation=null,但响应没有任何显式字段说明「该工单与当前报警无关」,前端只能靠 null 猜。app_user.equipment_point_rel 实测 0 行;monitor_point(6 行)没有 district 列。故「按后端现有关系输出可证明的逐条关系」在当前数据下只能如实输出「无关系 + 原因」,不能编造。district)| 事实 | 证据 |
|---|---|
| 权威来源已存在 | EquipmentBase.district(Integer,注释「0-城南 1-城北 2-太常,见 DistrictEnum」);DistrictEnum(base/enums/)含 SOUTH_CITY(0,"城南")/NORTH_CITY(1,"城北")/TAI_CHANG(2,"太常") 与 getByCode/getDescByCode/isValid |
| 真实数据齐备 | equipment_base 7 行,district 全部非空:0→4、1→2、2→1 |
| cockpit 代码零使用 district | 对 cockpit/** 全量 grep district 0 命中;现有实现只用旧自由串 region |
| region 实际恒为 null | BusinessCockpitMapSnapshotAdapter 第 234/251 行硬编码传 null,故服务层 regionOf() 一律归一为 未分区。实测地图首 3 个点位 region=未分区 |
| 设施与点位没有 district | PipeNetworkBase(管网设施)无 district 字段;monitor_point 无 district 列。只有设备(EquipmentBase)有 |
district 入参未被接受 |
实测 map-snapshot?district=0 被忽略(mapFilter 无该字段,入参不在控制器签名里);region=城南 被接受(自由文本、无校验、无白名单) |
涉及 region/regionDistribution 的响应族实测(4 族):
| 端点 | region 类字段 | 现状 |
|---|---|---|
/map-snapshot |
mapFilter.region、点位/设备 region |
入参可为自由串;值恒 未分区 |
/monitoring/distribution |
regionDistribution[]、marker region |
有;适配器注释明写「无可靠来源 → null → 未分区」 |
/monitoring/situation |
对象内 region |
有(同 null 归一) |
/infrastructure/base-archives |
regionDistribution[]、selectedFilters.region、mapFilter.region |
有(设施无 district 来源) |
/events/multidimensional-analysis |
dimensions 内 REGION 桶 |
有(UNASSIGNED_REGION/未分区 双常量) |
CockpitInfrastructureManagementInformationResponse 仍含 organizations、ownershipDistribution、Totals.unmaintainedCount、Organization.unmaintained/ownershipDistribution;实测 management-information 顶层字段含 organizations、ownershipDistribution。
耦合风险(实施时序需要裁定):前端 src/modules/cockpit/domain/infrastructurePanels.js 第 213–232 行正在读 organizations、ownershipDistribution、totals.unmaintainedCount,并用于面板渲染(第 433、441–446 行)。按决策 06「管理信息面板改片区×行业视图、后端删这三个字段」,后端先删会让前端面板读到空,需与前端票 15(管理面板片区化)对齐落地时序。
本票不能直接按字面实施:范围 2 的「统一按 district 过滤与回显」在点位与设施缺 district 来源的现实下无法字面达成(只有设备有);范围 3 的删除与前端存在时序耦合;范围 1 有 3 处语义缺口。故先请维护者裁定,不猜。
equipment_base.district)+ 点位经其上挂设备归纳;多设备不一致/无设备 → 未分区 并计数。不改 DDL、不给点位/设施加列(另开迁移票)。district(Integer,null=未分区)+ districtName(未分区时 "未分区");筛选入参 district=0|1|2,不传=全部,UNASSIGNED=只看未分区。符合决策 06「统计保留数字、展示层映射中文」。region 入参不再接受;响应中 region/regionDistribution 改为 district/districtDistribution。organizations / ownershipDistribution / unmaintained(含 Totals.unmaintainedCount);需回写前端票 15 同步改面板。alarm_data.work_order_id → work_order.order_id。维护者原述 alarm_data.alarm_no = work_order.order_no 经实测命中 0 条(work_order 无 alarm_no 列、alarm_data 无 order_no 列,order_no 为建单时独立生成),维护者已裁定采用 work_order_id。据此实现每张工单的显式关联标记。equipment_base 有 district;monitor_point 无该列、PipeNetworkBase 无该字段、equipment_point_rel 0 行。点位与设施的片区如何取?0/1/2 + 「未分区」哨兵)还是中文(城南/城北/太常)?region 入参的去留:直接以 district 取代(region 不再接受),还是并存过渡?work_order 多张工单的「当前工单」规则:后端无此规则,是否按决策 01「保留明细并声明规则缺失」实现(不引入新规则)?district(0/1/2 → 城南/城北/太常)过滤与回显;空值/乱码/未识别 → 未分区。region 不再作为正式范围契约(regionMap 过渡失效)。organizations / ownershipDistribution / unmaintained(按 #06 决策)。代码提交 + 编译 + 针对性契约测试 + 联调基线登记;本地联调通过后提交推送 Gogs。
| 项 | 状态 | 证据 |
|---|---|---|
| 编译 | 通过 | mvn -o -pl pipe-network-service/zksy-admin -am compile |
| 组合契约测试 | 通过 | -Dtest=Cockpit*Test,Business*AdapterTest → 372/372 |
| 联调基线登记 | 已产出 | 基线卡片 03 |
| 代码提交 + 推送 | 已完成 | 818a6d7 → origin/master(89ca989..818a6d7) |
| 真实环境复验 | 通过 | 见「状态」节复验表(8 项全通过) |
regionMap 配置映射失效、管理信息三字段消失、NO_ORGANIZATIONS 改名 NO_RELATIONS。region:'城区A' fixtures(离线样例,不阻塞契约,低优先)。4ef2159 已推 origin/master;全量 8 模块 414/414 通过。明细:WaterSupplyDeviceServiceImplTest 两处断言更新为「设备报警」、AlarmClearServiceTest 摘要断言更新为「监测报警」、AlarmReviewAttachmentServiceTest 整类删除(其断言的内容嗅探/伪造扩展名拦截为生产从未实现的策略,且测试环境必然 NPE)。