Bläddra i källkod

fix(waterSupply): 统一重建供水监测与报警测试数据并对齐真实设备类型 (#56)

- 退役 5 个失效种子(monitoring / device / abnormal / alarm_ledger / alarm_audit),
  由 sql/water_supply_monitoring_alarm_rebuild_test_data.sql 统一取代,幂等可重复执行
- 设备类型一律按库中真实 type_id 定位(ultrasonic_flowmeter / pressure_gauge / leak_monitor,
  parent_type_id=1),不新增任何设备类型;运行监测常量此前已对齐,本次由守卫测试锁死
- 非供水设备归位(燃气→3、排水→2、窨井→4),只删除带测试前缀的失效供水设备与死引用脏数据
- 重建后:供水设备 15 台(流量6/压力5/漏失4)、报警 16 条(四级齐全,展示状态 待审核7/已转工单7/已解除2)、
  工单 8 张(0..7 各一张,计数条 全部8/待处理2/处理中3/待验收1/已完成2)
- 新增 MonitoringFixtureTypeContractTest:SQL 不得再引用旧类型标识、旧种子不得回归、监测常量须与库一致
- 阈值种子改为引用新设备编码,文档同步指向统一脚本
Kazerin 1 månad sedan
förälder
incheckning
87c588fd45

+ 1 - 1
T6-water-device-handoff.md

@@ -32,7 +32,7 @@
   - 新增 `WaterDeviceLedgerExportDTO`、`WaterDeviceAbnormalExportDTO`。
   - 对应控制器测试已添加。
 - 测试数据
-  - 新增 `pipe-network-service/sql/water_supply_device_test_data.sql`,覆盖混合供水/非供水设备、正常/报警/维修/离线状态、异常原因和真实工单编号。
+- 测试数据统一由 `pipe-network-service/sql/water_supply_monitoring_alarm_rebuild_test_data.sql` 重建(原 `water_supply_device_test_data.sql` 已随 #56 退役),覆盖真实供水类型 11/12/14 下的设备、正常/报警/维修/离线状态、异常原因与真实工单编号。
 
 ### 前端
 

+ 2 - 2
pipe-network-service/docs/2026-09-14-water-supply-home-alarm-work-order-e2e.md

@@ -74,7 +74,7 @@
 - 需要覆盖的前端模块包括供水首页、设备异常管理、报警管理、报警审核和监测报警一张图,以及它们到统一工单页、右侧详情抽屉和导出的路由。
 - 测试数据优先使用专用种子数据或测试脚本,验收后如需清理则清理;不得依赖人工点击之外的外部状态。
 - 已有测试中若包含同类列表页、同类聚合接口测试,可作为先例;最终验收环境使用 KingbaseES。
-- 报警审核闭环的人工审查数据使用 `sql/water_supply_alarm_audit_test_data.sql`(T46- 前缀),覆盖待审核队列、五种工单状态、终态不占用唯一性名额和误报解除样本;文件头写明可对照的统计口径。
+- 报警审核闭环的人工审查数据统一由 `sql/water_supply_monitoring_alarm_rebuild_test_data.sql` 重建(幂等,可重复执行)。该脚本同时取代 `water_supply_monitoring_test_data.sql`、`water_supply_device_test_data.sql`、`water_supply_abnormal_test_data.sql`、`water_supply_alarm_ledger_test_data.sql`、`water_supply_alarm_audit_test_data.sql` 五个失效种子,覆盖 16 条报警(四级齐全、展示状态 待审核7/已转工单7/已解除2)、8 张工单(状态 0..7 各一张,计数条 全部8/待处理2/处理中3/待验收1/已完成2)与误报解除样本;口径写在文件头,执行后自检语句与之一致。
 
 ## Out of Scope
 
@@ -89,4 +89,4 @@
 
 - 本 Spec 以最新代码为权威,和已写入的 CONTEXT、工单生命周期文档以及 ADR-0010 保持一致。
 - 首页原型的 A、B、C 三块已确认,最终实现按纵向蓝白工作台落地。
-- 下一阶段在执行 `to-tickets` 时,每个 Ticket 应是可以演示的 tracer-bullet 垂直切片,并在 Gogs issue 中写明 Blocked by。
+- 下一阶段在执行 `to-tickets` 时,每个 Ticket 应是可以演示的 tracer-bullet 垂直切片,并在 Gogs issue 中写明 Blocked by。

+ 0 - 191
pipe-network-service/sql/water_supply_abnormal_test_data.sql

@@ -1,191 +0,0 @@
--- ============================================================
--- 供水管网 设备异常管理页面 测试数据脚本(KingbaseES)
--- 说明:
---   1. 测试主键与编号均使用 T6-ABN-TEST- / WO20260905 前缀,可重复执行。
---   2. 本脚本只初始化测试数据,不创建业务表;执行前请确认以下表已存在:
---      app_user.equipment_type、app_user.equipment_base、app_user.equipment_status、
---      app_user.alarm_data、app_user.work_order、app_user.work_order_log
---   3. 覆盖场景:
---      a. 有状态记录 + alarm_status=1 + 有效报警 -> 显示。
---      b. 有状态记录 + current_status=3 + 无有效报警 -> 显示,原因为设备维修中。
---      c. 无状态记录 + alarm_data.alarm_status=0 -> 显示(验证无状态回退修复)。
---      d. 无状态记录 + 无报警 -> 不显示。
---      e. 有状态记录但正常 + 仅存在已处理报警 -> 不显示。
---      f. 非供水设备 + 报警 -> 不显示。
--- ============================================================
-
--- ------------------------------------------------------------
--- 0. 清理历史测试数据(先清工单日志与工单,再清报警、状态、设备、临时类型)
--- ------------------------------------------------------------
-DELETE FROM app_user.work_order_log WHERE order_id IN
-    (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'WO20260905%' AND order_no IN (
-        'WO202609050001', 'WO202609050002', 'WO202609050003'
-    ));
-DELETE FROM app_user.work_order WHERE order_no IN
-    ('WO202609050001', 'WO202609050002', 'WO202609050003');
-DELETE FROM app_user.alarm_data WHERE id LIKE 'T6-ABN-TEST-ALARM-%';
-DELETE FROM app_user.equipment_status WHERE equipment_id LIKE 'T6-ABN-TEST-EQ-%';
-DELETE FROM app_user.equipment_base WHERE equipment_id LIKE 'T6-ABN-TEST-EQ-%';
-DELETE FROM app_user.equipment_type WHERE id = 'T6-ABN-TEST-GAS-TYPE';
-
--- ------------------------------------------------------------
--- 1. 校验规范供水设备类型,并创建临时非供水类型用于边界排除
--- ------------------------------------------------------------
-DO $$
-DECLARE
-    v_count integer;
-BEGIN
-    SELECT count(*) INTO v_count
-      FROM app_user.equipment_type
-     WHERE id = '1' AND parent_type_id = '0' AND type_name = '供水';
-    IF v_count <> 1 THEN
-        RAISE EXCEPTION '缺少规范供水顶级设备类型:id=1,type_name=供水,parent_type_id=0';
-    END IF;
-
-    SELECT count(*) INTO v_count
-      FROM app_user.equipment_type
-     WHERE type_id IN ('ws_flow', 'ws_pressure', 'ws_leak')
-       AND parent_type_id = '1';
-    IF v_count <> 3 THEN
-        RAISE EXCEPTION '缺少规范供水监测子类型:ws_flow/ws_pressure/ws_leak 必须 parent_type_id=1';
-    END IF;
-END $$;
-
-INSERT INTO app_user.equipment_type
-    (id, type_id, type_name, parent_type_id, type_remark)
-VALUES
-    ('T6-ABN-TEST-GAS-TYPE', 't6_abn_test_gas', '燃气(异常页测试)', '0',
-     'T6异常页非供水设备排除测试类型');
-
--- ------------------------------------------------------------
--- 2. 设备基础信息(6 台供水设备 + 1 台非供水设备)
---    注意:T6-ABN-TEST-EQ-NOSTATUS-ALARM 不插入 equipment_status,
---    专门用于验证 alarm_data.alarm_status=0 的无状态回退判定。
--- ------------------------------------------------------------
-INSERT INTO app_user.equipment_base
-    (equipment_id, equipment_code, equipment_name, equipment_model, equipment_type_id,
-     longitude, latitude, equipment_location, maintainer, maintainer_phone,
-     ownership_unit, remark, create_time, update_time, del_flag, district)
-VALUES
-    ('T6-ABN-TEST-EQ-ALARM-OPEN', 'CN-GS-202609050001', '异常页测试压力报警设备', 'PRESSURE-ABN-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1),
-     113.28000000, 23.12000000, '异常页测试大道1号', '异常页测试维护员', '13800000101',
-     '异常页测试供水公司', '设备异常管理测试数据', now() - interval '7 days', now(), '0', '城南'),
-    ('T6-ABN-TEST-EQ-ALARM-ORDERED', 'CB-GS-202609050002', '异常页测试压力已派单设备', 'PRESSURE-ABN-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1),
-     113.29000000, 23.13000000, '异常页测试大道2号', '异常页测试维护员', '13800000102',
-     '异常页测试供水公司', '设备异常管理测试数据', now() - interval '7 days', now(), '0', '城北'),
-    ('T6-ABN-TEST-EQ-REPAIR', 'TC-GS-202609050003', '异常页测试流量维修中设备', 'FLOW-ABN-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1),
-     113.30000000, 23.14000000, '异常页测试大道3号', '异常页测试维护员', '13800000103',
-     '异常页测试供水公司', '设备异常管理测试数据', now() - interval '7 days', now(), '0', '太常'),
-    ('T6-ABN-TEST-EQ-NOSTATUS-ALARM', 'CN-GS-202609050004', '异常页测试无状态报警设备', 'LEAK-ABN-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_leak' AND parent_type_id = '1' LIMIT 1),
-     113.31000000, 23.15000000, '异常页测试大道4号', '异常页测试维护员', '13800000104',
-     '异常页测试供水公司', '设备异常管理测试数据', now() - interval '7 days', now(), '0', '城南'),
-    ('T6-ABN-TEST-EQ-NORMAL-HIDDEN', 'CB-GS-202609050005', '异常页测试正常隐藏设备', 'FLOW-ABN-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1),
-     113.32000000, 23.16000000, '异常页测试大道5号', '异常页测试维护员', '13800000105',
-     '异常页测试供水公司', '设备异常管理测试数据', now() - interval '7 days', now(), '0', '城北'),
-    ('T6-ABN-TEST-EQ-NOSTATUS-HIDDEN', 'TC-GS-202609050007', '异常页测试无状态隐藏设备', 'PRESSURE-ABN-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1),
-     113.33000000, 23.17000000, '异常页测试大道7号', '异常页测试维护员', '13800000107',
-     '异常页测试供水公司', '设备异常管理测试数据', now() - interval '7 days', now(), '0', '太常'),
-    ('T6-ABN-TEST-EQ-GAS-EXCLUDED', 'CN-RQ-202609050006', '异常页测试燃气排除设备', 'GAS-ABN-TEST',
-     'T6-ABN-TEST-GAS-TYPE', 113.34000000, 23.18000000, '异常页测试大道6号',
-     '异常页测试维护员', '13800000106', '异常页测试燃气公司', '非供水设备排除测试数据',
-     now() - interval '7 days', now(), '0', '城南');
-
--- ------------------------------------------------------------
--- 3. 设备状态
--- ------------------------------------------------------------
-INSERT INTO app_user.equipment_status
-    (equipment_id, current_status, alarm_status, online_status,
-     installation_addr, status_update_time, create_time, del_flag)
-VALUES
-    ('T6-ABN-TEST-EQ-ALARM-OPEN', 1, 1, 1, '异常页测试大道1号',
-     now() - interval '1 hour', now() - interval '1 hour', '0'),
-    ('T6-ABN-TEST-EQ-ALARM-ORDERED', 1, 1, 1, '异常页测试大道2号',
-     now() - interval '2 hours', now() - interval '2 hours', '0'),
-    ('T6-ABN-TEST-EQ-REPAIR', 3, 0, 1, '异常页测试大道3号',
-     now() - interval '3 hours', now() - interval '3 hours', '0'),
-    ('T6-ABN-TEST-EQ-NORMAL-HIDDEN', 1, 0, 1, '异常页测试大道5号',
-     now() - interval '5 hours', now() - interval '5 hours', '0'),
-    ('T6-ABN-TEST-EQ-GAS-EXCLUDED', 1, 1, 1, '异常页测试大道6号',
-     now() - interval '6 hours', now() - interval '6 hours', '0');
-
--- ------------------------------------------------------------
--- 4. 报警数据
---    alarm_status=0 表示未处置/有效报警;alarm_status=1 表示已处理报警。
--- ------------------------------------------------------------
-INSERT INTO app_user.alarm_data
-    (id, device_code, device_name, device_type, warning_type, warning_code,
-     min_value, max_value, actual_value, alarm_level, deviation_ratio,
-     alarm_status, alarm_time, handle_time, handle_user, handle_remark, remark,
-     create_time, update_time)
-VALUES
-    ('T6-ABN-TEST-ALARM-OPEN', 'CN-GS-202609050001', '异常页测试压力报警设备', '压力监测',
-     '供水压力超限', 'WARN-ABN-PRESSURE-OPEN', 0.20, 0.80, 1.20, 1, 50.00,
-     0, now() - interval '1 hour', NULL, NULL, NULL, '设备异常管理测试数据',
-     now() - interval '1 hour', now() - interval '1 hour'),
-    ('T6-ABN-TEST-ALARM-ORDERED', 'CB-GS-202609050002', '异常页测试压力已派单设备', '压力监测',
-     '供水压力异常', 'WARN-ABN-PRESSURE-ORDERED', 0.20, 0.80, 0.95, 2, 18.75,
-     0, now() - interval '2 hours', NULL, NULL, NULL, '设备异常管理测试数据',
-     now() - interval '2 hours', now() - interval '2 hours'),
-    ('T6-ABN-TEST-ALARM-NOSTATUS', 'CN-GS-202609050004', '异常页测试无状态报警设备', '漏失监测',
-     '供水漏失异常', 'WARN-ABN-LEAK-NOSTATUS', 0.00, 5.00, 8.00, 3, 60.00,
-     0, now() - interval '3 hours', NULL, NULL, NULL, '设备异常管理测试数据',
-     now() - interval '3 hours', now() - interval '3 hours'),
-    ('T6-ABN-TEST-ALARM-NORMAL-RESOLVED', 'CB-GS-202609050005', '异常页测试正常隐藏设备', '流量监测',
-     '供水流量波动', 'WARN-ABN-FLOW-RESOLVED', 1.00, 10.00, 12.00, 4, 20.00,
-     1, now() - interval '5 hours', now() - interval '4 hours', 'admin', '测试已处理报警',
-     '设备异常管理测试数据', now() - interval '5 hours', now() - interval '4 hours'),
-    ('T6-ABN-TEST-ALARM-GAS-EXCLUDED', 'CN-RQ-202609050006', '异常页测试燃气排除设备', '燃气监测',
-     '燃气浓度超限', 'WARN-ABN-GAS-EXCLUDED', 0.00, 20.00, 45.00, 1, 125.00,
-     0, now() - interval '6 hours', NULL, NULL, NULL, '非供水设备排除测试数据',
-     now() - interval '6 hours', now() - interval '6 hours');
-
--- ------------------------------------------------------------
--- 5. 关联统一工单(order_type=1 表示故障维修)
---    WO202609050001 为已结案工单,不应阻止报警设备重新派单。
---    WO202609050002/003 为未结束工单,dispatchableOnly=true 时对应设备应被排除。
--- ------------------------------------------------------------
-INSERT INTO app_user.work_order
-    (order_no, alarm_id, case_id, case_no, device_id, device_code,
-     order_type, order_level, order_desc, dept_id, dispatch_user, dispatch_time,
-     receive_user, order_status, delayed_reason, delayed_deadline, plan_finish_time,
-     real_finish_time, repair_result, maintenance_before_img, maintenance_after_img,
-     verify_user, verify_time, create_time, update_time)
-VALUES
-    ('WO202609050001', 'T6-ABN-TEST-ALARM-OPEN', NULL, NULL,
-     'T6-ABN-TEST-EQ-ALARM-OPEN', 'CN-GS-202609050001',
-     1, 1, '异常页测试历史已结案维修工单', NULL, NULL, now() - interval '55 minutes',
-     '1', 6, NULL, NULL, now() - interval '10 minutes',
-     now() - interval '15 minutes', '测试结案', NULL, NULL,
-     '1', now() - interval '12 minutes', now() - interval '55 minutes', now()),
-    ('WO202609050002', 'T6-ABN-TEST-ALARM-ORDERED', NULL, NULL,
-     'T6-ABN-TEST-EQ-ALARM-ORDERED', 'CB-GS-202609050002',
-     1, 2, '异常页测试压力报警处理中工单', NULL, NULL, now() - interval '110 minutes',
-     '2', 4, NULL, NULL, now() + interval '1 day',
-     NULL, NULL, NULL, NULL, NULL,
-     NULL, now() - interval '110 minutes', now()),
-    ('WO202609050003', NULL, NULL, NULL,
-     'T6-ABN-TEST-EQ-REPAIR', 'TC-GS-202609050003',
-     1, 3, '异常页测试流量设备维修中工单', NULL, NULL, now() - interval '3 hours',
-     '3', 4, NULL, NULL, now() + interval '2 days',
-     NULL, NULL, NULL, NULL, NULL,
-     NULL, now() - interval '3 hours', now());
-
--- ============================================================
--- 快速核验:
---   1. 设备异常管理页应显示 4 台供水设备:
---      CN-GS-202609050001(供水压力超限,可派单)。
---      CB-GS-202609050002(供水压力异常,已派单)。
---      TC-GS-202609050003(设备维修中,已派单)。
---      CN-GS-202609050004(供水漏失异常,无状态记录但有效报警,可派单)。
---   2. CB-GS-202609050005 不应显示:状态正常,且只有已处理报警。
---   3. TC-GS-202609050007 不应显示:无状态记录且无有效报警。
---   4. CN-RQ-202609050006 不应显示:属于非供水设备。
---   5. dispatchableOnly=true 时,只应返回
---      CN-GS-202609050001 和 CN-GS-202609050004。
--- ============================================================

+ 0 - 246
pipe-network-service/sql/water_supply_alarm_audit_test_data.sql

@@ -1,246 +0,0 @@
--- ============================================================
--- 供水监测报警模块 现状验收测试数据(#46 T03 收口 / 供人工审查)
--- 数据库:人大金仓 KingbaseES(PostgreSQL 语法兼容)
---
--- 说明:
---   1. 全部数据使用 T46- / t46- 前缀,与 T45-(报警台账)等既有种子互不干扰。
---   2. 先删后插,可重复执行;清理语句见文件末尾。
---   3. 设备编码遵循命名规范:区域(CN城南/CB城北/TC太常)-类型(GS供水)-YYYYMMDD+4位流水号。
---   4. 工单表按重构后的结构写入:不再有 order_type 列;dispatch_user / receive_user 为 BIGINT 用户ID。
---   5. 设备类型不新增:一律引用库中现有 equipment_type
---      (type_id = pressure_gauge / ultrasonic_flowmeter / leak_monitor 且 parent_type_id = '1'),
---      equipment_base.equipment_type_id 写入该类型记录的 id;找不到类型时脚本直接报错,不做兜底新增。
---   6. dept_id 统一取 100(顶级部门)。若审核账号使用「本部门」数据范围且所属部门不是 100,
---      请把下方 dept_id 改成该账号的部门ID,否则统一工单页按部门过滤后看不到这批工单。
---
--- 审查对照口径:
---   A. 报警审核页顶部计数条(只统计供水设备且 alarm_id 非空的工单)
---      全部 7 ;待处理(0,1) 2 ;处理中(2,3,6) 2 ;待验收(4) 1 ;已完成(5,7) 2
---   B. 报警审核队列(展示状态=待审核)应显示 8 条
---      a01 a02 a03 a04 a05 a06(无工单) + a12 a13(仅关联终态工单,终态不占用唯一性名额)
---   C. 报警管理展示状态分布:待审核 8 / 已转工单 5 / 已解除 1
---   D. 设备报警状态:报警中 = 设备1、设备2、设备6(状态表 alarm_status=1)与设备5(无状态记录时的回退分支)
---      正常 = 设备3 ;另有设备4 为离线(alarm_status=0 且 online_status=0)
---   E. 同类工单唯一性(同设备 + 同报警类型 + 未办结)
---      应被阻止:a01、a06(设备1 压力预警已有 WO-001 未办结)
---      应被允许:a12、a13(设备6 漏失预警只有 已结案/已取消 两张终态工单)
---   F. 误报解除样本:a14 已写入审核结论=2(误报),展示状态应为「已解除」,且不产生工单
---
--- 已知现状(非缺陷,供确认):误报解除与工单结案都不会清除设备报警状态,
---   设备报警状态由运行系统负责(见 ADR-0002)。清警能力缺失已另立 #51。
--- ============================================================
-
--- ------------------------------------------------------------
--- 0. 清理历史数据(保证可重复执行)
--- ------------------------------------------------------------
-DELETE FROM app_user.alarm_audit       WHERE alarm_id LIKE 't46-alarm-%';
-DELETE FROM app_user.work_order_log    WHERE order_id IN
-    (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'T46-WO-%');
-DELETE FROM app_user.work_order        WHERE order_no LIKE 'T46-WO-%' OR alarm_id LIKE 't46-alarm-%';
-DELETE FROM app_user.alarm_data        WHERE id LIKE 't46-alarm-%';
-DELETE FROM app_user.warning_threshold WHERE id LIKE 't46-thr-%' OR device_code LIKE 'T46-%';
-DELETE FROM app_user.equipment_status  WHERE equipment_id LIKE 'T46-EQ-%';
-DELETE FROM app_user.equipment_base    WHERE equipment_id LIKE 'T46-EQ-%';
-
--- ------------------------------------------------------------
--- 1. 设备台账(设备类型引用库中现有 equipment_type,不新增类型)
--- ------------------------------------------------------------
-DO $$
-DECLARE
-    v_pressure_id varchar(64);
-    v_flow_id     varchar(64);
-    v_leak_id     varchar(64);
-BEGIN
-    -- 设备类型以库中现有 equipment_type 为权威:本脚本不新增任何设备类型,
-    -- 按 type_id + parent_type_id 定位后取出 id,供 equipment_base.equipment_type_id 使用。
-    SELECT id INTO v_pressure_id FROM app_user.equipment_type
-     WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1;
-    SELECT id INTO v_flow_id FROM app_user.equipment_type
-     WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1;
-    SELECT id INTO v_leak_id FROM app_user.equipment_type
-     WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1;
-
-    IF v_pressure_id IS NULL OR v_flow_id IS NULL OR v_leak_id IS NULL THEN
-        RAISE EXCEPTION 'equipment_type 缺少供水监测类型(pressure_gauge / ultrasonic_flowmeter / leak_monitor 且 parent_type_id=1),请先核对现有类型数据';
-    END IF;
-    INSERT INTO app_user.equipment_base
-        (equipment_id, equipment_code, equipment_name, equipment_model, equipment_type_id,
-         longitude, latitude, equipment_location, maintainer, maintainer_phone, ownership_unit,
-         remark, create_time, update_time, del_flag, district)
-    VALUES
-        ('T46-EQ-PR-CN', 'CN-GS-202609160101', '城南加压站压力监测点', 'T46-PR-1', v_pressure_id,
-         113.28100000, 23.12100000, '城南大道101号', '张巡维', '13800000201', '市供水公司',
-         '#46报警审核测试数据', now(), now(), '0', '城南'),
-        ('T46-EQ-PR-CB', 'CB-GS-202609160102', '城北末梢压力监测点', 'T46-PR-2', v_pressure_id,
-         113.31200000, 23.17200000, '城北大道102号', '李巡维', '13800000202', '市供水公司',
-         '#46报警审核测试数据', now(), now(), '0', '城北'),
-        ('T46-EQ-FL-TC', 'TC-GS-202609160103', '太常厂区流量监测点', 'T46-FL-1', v_flow_id,
-         113.25100000, 23.09100000, '太常路103号', '王巡维', '13800000203', '市供水公司',
-         '#46报警审核测试数据', now(), now(), '0', '太常'),
-        ('T46-EQ-LK-CN', 'CN-GS-202609160104', '城南漏失声波监测点', 'T46-LK-1', v_leak_id,
-         113.28600000, 23.12600000, '城南大道104号', '赵巡维', '13800000204', '市供水公司',
-         '#46报警审核测试数据', now(), now(), '0', '城南'),
-        ('T46-EQ-FL-CB', 'CB-GS-202609160105', '城北出厂流量监测点', 'T46-FL-2', v_flow_id,
-         113.31600000, 23.17600000, '城北大道105号', '孙巡维', '13800000205', '市供水公司',
-         '#46无设备状态记录-回退分支', now(), now(), '0', '城北'),
-        ('T46-EQ-LK-TC', 'TC-GS-202609160106', '太常漏失声波监测点', 'T46-LK-2', v_leak_id,
-         113.25600000, 23.09600000, '太常路106号', '周巡维', '13800000206', '市供水公司',
-         '#46终态工单与误报解除样本', now(), now(), '0', '太常');
-END $$;
-
--- ------------------------------------------------------------
--- 2. 设备状态(equipment_status)
---    设备5(T46-EQ-FL-CB)刻意不建记录,用于验证设备报警状态回退分支
--- ------------------------------------------------------------
-INSERT INTO app_user.equipment_status
-    (equipment_id, current_status, alarm_status, online_status,
-     installation_addr, status_update_time, create_time, del_flag)
-VALUES
-    ('T46-EQ-PR-CN', 1, 1, 1, '城南大道101号', now() - interval '30 minutes', now(), '0'),
-    ('T46-EQ-PR-CB', 1, 1, 1, '城北大道102号', now() - interval '40 minutes', now(), '0'),
-    ('T46-EQ-FL-TC', 1, 0, 1, '太常路103号',   now() - interval '50 minutes', now(), '0'),
-    ('T46-EQ-LK-CN', 1, 0, 0, '城南大道104号', now() - interval '2 hours',    now(), '0'),
-    ('T46-EQ-LK-TC', 1, 1, 1, '太常路106号',   now() - interval '3 hours',    now(), '0');
-
--- ------------------------------------------------------------
--- 3. 阈值(warning_threshold)
--- ------------------------------------------------------------
-INSERT INTO app_user.warning_threshold
-    (id, device_code, warning_type, warning_code, min_value, max_value,
-     period_start, period_end, remark, create_time, update_time)
-VALUES
-    ('t46-thr-001', 'CN-GS-202609160101', '压力预警', 'T46-WARN-PRESSURE', 0.40, 0.80,
-     NULL, NULL, '#46测试-全天阈值', now(), now()),
-    ('t46-thr-002', 'CB-GS-202609160102', '压力预警', 'T46-WARN-PRESSURE', 0.35, 0.85,
-     NULL, NULL, '#46测试-全天阈值', now(), now()),
-    ('t46-thr-003', 'TC-GS-202609160103', '流量预警', 'T46-WARN-FLOW', 10.00, 100.00,
-     '08:00', '20:00', '#46测试-分时阈值(08:00-20:00)', now(), now()),
-    ('t46-thr-004', 'CN-GS-202609160104', '漏失预警', 'T46-WARN-LEAK', 0.00, 5.00,
-     NULL, NULL, '#46测试-阈值下限为0', now(), now()),
-    ('t46-thr-005', 'CB-GS-202609160105', '流量预警', 'T46-WARN-FLOW', 8.00, 120.00,
-     NULL, NULL, '#46测试-全天阈值', now(), now()),
-    ('t46-thr-006', 'TC-GS-202609160106', '漏失预警', 'T46-WARN-LEAK', 0.00, 5.00,
-     NULL, NULL, '#46测试-全天阈值', now(), now());
-
--- ------------------------------------------------------------
--- 4. 报警流水(alarm_data)
---    alarm_status:0-未处理 1-已处理;alarm_level:1 最高
--- ------------------------------------------------------------
-INSERT INTO app_user.alarm_data
-    (id, device_code, device_name, device_type, warning_type, warning_code,
-     actual_value, min_value, max_value, alarm_status, alarm_level, deviation_ratio,
-     alarm_time, handle_time, handle_user, handle_remark, remark, create_time, update_time)
-VALUES
-    -- 待审核:无关联工单
-    ('t46-alarm-a01', 'CN-GS-202609160101', '城南加压站压力监测点', '压力监测', '压力预警', 'T46-WARN-PRESSURE',
-     0.95, 0.40, 0.80, 0, 1, 18.75, now() - interval '35 minutes', NULL, NULL, NULL,
-     '#46待审核-设备1压力一级(同设备同类型已有WO-001未办结,转工单应被阻止)', now(), now()),
-    ('t46-alarm-a02', 'CB-GS-202609160102', '城北末梢压力监测点', '压力监测', '压力预警', 'T46-WARN-PRESSURE',
-     0.90, 0.35, 0.85, 0, 2, 5.88, now() - interval '30 minutes', NULL, NULL, NULL,
-     '#46待审核-设备2压力二级', now(), now()),
-    ('t46-alarm-a03', 'TC-GS-202609160103', '太常厂区流量监测点', '流量监测', '流量预警', 'T46-WARN-FLOW',
-     112.00, 10.00, 100.00, 0, 3, 12.00, now() - interval '25 minutes', NULL, NULL, NULL,
-     '#46待审核-设备3流量三级', now(), now()),
-    ('t46-alarm-a04', 'CN-GS-202609160104', '城南漏失声波监测点', '漏失监测', '漏失预警', 'T46-WARN-LEAK',
-     7.20, 0.00, 5.00, 0, 4, 44.00, now() - interval '20 minutes', NULL, NULL, NULL,
-     '#46待审核-设备4漏失四级(设备离线)', now(), now()),
-    ('t46-alarm-a05', 'CB-GS-202609160105', '城北出厂流量监测点', '流量监测', '流量预警', 'T46-WARN-FLOW',
-     3.20, 8.00, 120.00, 0, 2, 60.00, now() - interval '15 minutes', NULL, NULL, NULL,
-     '#46待审核-设备5无状态记录(设备报警状态走回退分支)', now(), now()),
-    ('t46-alarm-a06', 'CN-GS-202609160101', '城南加压站压力监测点', '压力监测', '压力预警', 'T46-WARN-PRESSURE',
-     0.28, 0.40, 0.80, 0, 1, 30.00, now() - interval '1 day' - interval '10 minutes', NULL, NULL, NULL,
-     '#46待审核-设备1压力一级(第二条同类型报警)', now(), now()),
-
-    -- 已转工单:关联未办结工单(0/1/3/6/4)
-    ('t46-alarm-a07', 'CN-GS-202609160101', '城南加压站压力监测点', '压力监测', '压力预警', 'T46-WARN-PRESSURE',
-     0.88, 0.40, 0.80, 0, 1, 10.00, now() - interval '6 hours', NULL, NULL, NULL,
-     '#46已转工单-WO-001 待派单', now(), now()),
-    ('t46-alarm-a08', 'CB-GS-202609160102', '城北末梢压力监测点', '压力监测', '压力预警', 'T46-WARN-PRESSURE',
-     0.30, 0.35, 0.85, 0, 2, 14.29, now() - interval '7 hours', NULL, NULL, NULL,
-     '#46已转工单-WO-002 待接单', now(), now()),
-    ('t46-alarm-a09', 'TC-GS-202609160103', '太常厂区流量监测点', '流量监测', '流量预警', 'T46-WARN-FLOW',
-     130.50, 10.00, 100.00, 0, 1, 30.50, now() - interval '1 day' - interval '2 hours', NULL, NULL, NULL,
-     '#46已转工单-WO-003 处理中', now(), now()),
-    ('t46-alarm-a10', 'CB-GS-202609160105', '城北出厂流量监测点', '流量监测', '流量预警', 'T46-WARN-FLOW',
-     140.00, 8.00, 120.00, 0, 3, 16.67, now() - interval '2 days', NULL, NULL, NULL,
-     '#46已转工单-WO-004 延期中', now(), now()),
-    ('t46-alarm-a11', 'CN-GS-202609160104', '城南漏失声波监测点', '漏失监测', '漏失预警', 'T46-WARN-LEAK',
-     6.10, 0.00, 5.00, 0, 2, 22.00, now() - interval '3 days', NULL, NULL, NULL,
-     '#46已转工单-WO-005 待验收', now(), now()),
-
-    -- 仅关联终态工单:终态不占用唯一性名额,展示状态回到「待审核」
-    ('t46-alarm-a12', 'TC-GS-202609160106', '太常漏失声波监测点', '漏失监测', '漏失预警', 'T46-WARN-LEAK',
-     5.80, 0.00, 5.00, 0, 1, 16.00, now() - interval '4 days', NULL, NULL, NULL,
-     '#46待审核-仅关联WO-006(已结案),转工单应被允许', now(), now()),
-    ('t46-alarm-a13', 'TC-GS-202609160106', '太常漏失声波监测点', '漏失监测', '漏失预警', 'T46-WARN-LEAK',
-     6.40, 0.00, 5.00, 0, 3, 28.00, now() - interval '5 days', NULL, NULL, NULL,
-     '#46待审核-仅关联WO-007(已取消),转工单应被允许', now(), now()),
-
-    -- 误报解除样本:已写审核结论=2,不产生工单
-    ('t46-alarm-a14', 'TC-GS-202609160106', '太常漏失声波监测点', '漏失监测', '漏失预警', 'T46-WARN-LEAK',
-     5.20, 0.00, 5.00, 0, 4, 4.00, now() - interval '6 days', NULL, NULL, NULL,
-     '#46已解除-误报(审核结论=2,不产生工单)', now(), now());
-
--- ------------------------------------------------------------
--- 5. 关联工单(work_order)
---    状态:0-待派单 1-待接单 2-已接单 3-处理中 4-待验收 5-已结案 6-延期中 7-已取消
---    无 order_type 列;用户ID列为 BIGINT;dept_id 见文件头说明
--- ------------------------------------------------------------
-INSERT INTO app_user.work_order
-    (order_no, alarm_id, device_id, device_code, order_level, order_desc, dept_id,
-     dispatch_user, dispatch_time, receive_user, order_status, fault_time, create_time, update_time)
-VALUES
-    ('T46-WO-001', 't46-alarm-a07', 'T46-EQ-PR-CN', 'CN-GS-202609160101', 0,
-     '#46测试工单-城南压力超限待派单', 100, NULL, NULL, NULL, 0,
-     now() - interval '6 hours', now(), now()),
-    ('T46-WO-002', 't46-alarm-a08', 'T46-EQ-PR-CB', 'CB-GS-202609160102', 1,
-     '#46测试工单-城北压力偏低待接单', 100, 1, now() - interval '7 hours', NULL, 1,
-     now() - interval '7 hours', now(), now()),
-    ('T46-WO-003', 't46-alarm-a09', 'T46-EQ-FL-TC', 'TC-GS-202609160103', 0,
-     '#46测试工单-太常流量超限处理中', 100, 1, now() - interval '1 day', 2, 3,
-     now() - interval '1 day' - interval '2 hours', now(), now()),
-    ('T46-WO-004', 't46-alarm-a10', 'T46-EQ-FL-CB', 'CB-GS-202609160105', 1,
-     '#46测试工单-城北出厂流量延期中', 100, 1, now() - interval '2 days', 2, 6,
-     now() - interval '2 days', now(), now()),
-    ('T46-WO-005', 't46-alarm-a11', 'T46-EQ-LK-CN', 'CN-GS-202609160104', 1,
-     '#46测试工单-城南漏失待验收', 100, 1, now() - interval '3 days', 2, 4,
-     now() - interval '3 days', now(), now()),
-    ('T46-WO-006', 't46-alarm-a12', 'T46-EQ-LK-TC', 'TC-GS-202609160106', 0,
-     '#46测试工单-太常漏失已结案', 100, 1, now() - interval '4 days', 2, 5,
-     now() - interval '4 days', now(), now()),
-    ('T46-WO-007', 't46-alarm-a13', 'T46-EQ-LK-TC', 'TC-GS-202609160106', 1,
-     '#46测试工单-太常漏失已取消', 100, 1, now() - interval '5 days', NULL, 7,
-     now() - interval '5 days', now(), now());
-
-INSERT INTO app_user.work_order_log
-    (order_id, oper_type, oper_desc, oper_user_id, oper_user_name, oper_time)
-SELECT order_id, 0, '#46测试-报警审核转工单创建', 1, '调度管理员', now()
-  FROM app_user.work_order WHERE order_no LIKE 'T46-WO-%';
-
--- ------------------------------------------------------------
--- 6. 报警审核记录(alarm_audit)
---    audit_action 1-转工单 2-误报解除;audit_result 1-属实 2-误报
--- ------------------------------------------------------------
-INSERT INTO app_user.alarm_audit
-    (alarm_id, audit_action, audit_result, audit_opinion, attach_url,
-     audit_user_id, audit_user_name, audit_time, create_time, update_time)
-VALUES
-    ('t46-alarm-a07', 1, 1, '#46测试审核:压力超限属实,转故障维修工单', NULL,
-     1, '调度管理员', now() - interval '6 hours', now(), now()),
-    ('t46-alarm-a09', 1, 1, '#46测试审核:流量超限属实,转故障维修工单', NULL,
-     1, '调度管理员', now() - interval '1 day', now(), now()),
-    ('t46-alarm-a14', 2, 2, '#46测试审核:现场核实为误报,解除报警且不生成工单',
-     'https://example.com/t46-false-alarm-evidence.jpg',
-     1, '调度管理员', now() - interval '6 days', now(), now());
-
--- ============================================================
--- 清理脚本(如需移除本批测试数据,执行以下语句)
--- ============================================================
--- DELETE FROM app_user.alarm_audit       WHERE alarm_id LIKE 't46-alarm-%';
--- DELETE FROM app_user.work_order_log    WHERE order_id IN
---     (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'T46-WO-%');
--- DELETE FROM app_user.work_order        WHERE order_no LIKE 'T46-WO-%' OR alarm_id LIKE 't46-alarm-%';
--- DELETE FROM app_user.alarm_data        WHERE id LIKE 't46-alarm-%';
--- DELETE FROM app_user.warning_threshold WHERE id LIKE 't46-thr-%' OR device_code LIKE 'T46-%';
--- DELETE FROM app_user.equipment_status  WHERE equipment_id LIKE 'T46-EQ-%';
--- DELETE FROM app_user.equipment_base    WHERE equipment_id LIKE 'T46-EQ-%';

+ 0 - 260
pipe-network-service/sql/water_supply_alarm_ledger_test_data.sql

@@ -1,260 +0,0 @@
--- ============================================================
--- 供水报警管理只读台账与态势统计(Gogs #45 / T02)验收测试数据
--- 数据库:人大金仓 KingbaseES(PostgreSQL 语法兼容)
---
--- 说明:
---   1. 全部测试数据使用 T45- / t45- 前缀,与既有 TEST- 种子互不干扰。
---   2. 先删后插,可重复执行;清理语句见文件末尾。
---   3. 设备编码遵循项目命名规范:区域(CN城南/CB城北/TC太常)-类型(GS供水)-YYYYMMDD+4位流水号。
---   4. 设备类型不新增:一律引用库中现有 equipment_type
---      (type_id = pressure_gauge / ultrasonic_flowmeter / leak_monitor 且 parent_type_id = '1'),
---      equipment_base.equipment_type_id 写入该类型记录的 id;找不到类型时脚本直接报错,不做兜底新增。
---
--- 本批数据刻意覆盖以下验收点:
---   · 报警趋势四条等级序列:近 7 天内每天至少一个等级有值,且四级都出现过
---   · 三种报警展示状态:待审核 / 已转工单 / 已解除
---   · 设备报警状态两种取值:报警中(1) 与 正常(0),另有 1 台离线设备
---   · 关联工单:未办结工单→已转工单;已结案/已取消工单→不得算作已转工单
---   · 无 equipment_status 记录时的设备报警状态回退分支
---   · 报警值为空、阈值未配置、阈值下限为 0 三种边界显示
---   · 窗口外(8/12 天前)的报警,用于验证时间范围查询与趋势补零
---
--- 台账预期口径(15 条报警,执行后应与页面一致):
---   报警总数 15;待审核 9;已转工单 2;已解除 4;报警中设备 3(城南压力、太常流量、城北流量-兜底)
---   趋势(近 7 天,按等级):
---     今日       一级1 二级2 三级1 四级1
---     昨日       一级1 二级0 三级1 四级0
---     前2日      一级1 二级1 三级0 四级0
---     前3日      一级1 二级0 三级0 四级0
---     前4日      一级0 二级0 三级0 四级1
---     前5日      一级0 二级0 三级1 四级0
---     前6日      一级0 二级0 三级0 四级1
---   报警分类占比:压力预警6 / 流量预警5 / 漏失预警4
---   设备分类占比:压力监测6 / 流量监测5 / 漏失监测4
---   报警等级占比:一级5 / 二级4 / 三级3 / 四级3
--- ============================================================
-
--- ------------------------------------------------------------
--- 0. 清理历史数据(保证可重复执行)
--- ------------------------------------------------------------
-DELETE FROM app_user.alarm_audit      WHERE alarm_id LIKE 't45-alarm-%';
-DELETE FROM app_user.work_order_log   WHERE order_id IN
-    (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'T45-WO-%');
-DELETE FROM app_user.work_order       WHERE order_no LIKE 'T45-WO-%' OR alarm_id LIKE 't45-alarm-%';
-DELETE FROM app_user.alarm_data       WHERE id LIKE 't45-alarm-%';
-DELETE FROM app_user.warning_threshold WHERE id LIKE 't45-thr-%' OR device_code LIKE 'T45-%';
-DELETE FROM app_user.equipment_status WHERE equipment_id LIKE 'T45-EQ-%';
-DELETE FROM app_user.equipment_base   WHERE equipment_id LIKE 'T45-EQ-%';
-
--- ------------------------------------------------------------
--- 1. 设备类型(挂在顶级类型“供水”之下)与设备基础信息
--- ------------------------------------------------------------
-DO $$
-DECLARE
-    v_pressure_id varchar(64);
-    v_flow_id     varchar(64);
-    v_leak_id     varchar(64);
-BEGIN
-    -- 设备类型以库中现有 equipment_type 为权威:本脚本不新增任何设备类型,
-    -- 按 type_id + parent_type_id 定位后取出 id,供 equipment_base.equipment_type_id 使用。
-    SELECT id INTO v_pressure_id FROM app_user.equipment_type
-     WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1;
-    SELECT id INTO v_flow_id FROM app_user.equipment_type
-     WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1;
-    SELECT id INTO v_leak_id FROM app_user.equipment_type
-     WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1;
-
-    IF v_pressure_id IS NULL OR v_flow_id IS NULL OR v_leak_id IS NULL THEN
-        RAISE EXCEPTION 'equipment_type 缺少供水监测类型(pressure_gauge / ultrasonic_flowmeter / leak_monitor 且 parent_type_id=1),请先核对现有类型数据';
-    END IF;
-    INSERT INTO app_user.equipment_base
-        (equipment_id, equipment_code, equipment_name, equipment_model, equipment_type_id,
-         longitude, latitude, equipment_location, maintainer, maintainer_phone, ownership_unit,
-         remark, create_time, update_time, del_flag, district)
-    VALUES
-        -- 报警中:设备状态 alarm_status=1
-        ('T45-EQ-PR-CN', 'CN-GS-202609160001', '城南加压站压力监测点', 'T45-PR-1', v_pressure_id,
-         113.28000000, 23.12000000, '城南大道1号', '张巡维', '13800000101', '市供水公司',
-         '#45报警台账测试数据', now(), now(), '0', '城南'),
-        -- 正常:设备状态 alarm_status=0
-        ('T45-EQ-PR-CB', 'CB-GS-202609160002', '城北末梢压力监测点', 'T45-PR-2', v_pressure_id,
-         113.31000000, 23.17000000, '城北大道2号', '李巡维', '13800000102', '市供水公司',
-         '#45报警台账测试数据', now(), now(), '0', '城北'),
-        -- 报警中:用于流量分类
-        ('T45-EQ-FL-TC', 'TC-GS-202609160003', '太常厂区流量监测点', 'T45-FL-1', v_flow_id,
-         113.25000000, 23.09000000, '太常路3号', '王巡维', '13800000103', '市供水公司',
-         '#45报警台账测试数据', now(), now(), '0', '太常'),
-        -- 正常但离线:设备报警状态与在线状态分离
-        ('T45-EQ-LK-CN', 'CN-GS-202609160004', '城南漏失声波监测点', 'T45-LK-1', v_leak_id,
-         113.28500000, 23.12500000, '城南大道4号', '赵巡维', '13800000104', '市供水公司',
-         '#45报警台账测试数据', now(), now(), '0', '城南'),
-        -- 故意不建 equipment_status 记录:验证设备报警状态回退分支
-        ('T45-EQ-FL-CB', 'CB-GS-202609160005', '城北出厂流量监测点', 'T45-FL-2', v_flow_id,
-         113.31500000, 23.17500000, '城北大道5号', '孙巡维', '13800000105', '市供水公司',
-         '#45报警台账测试数据', now(), now(), '0', '城北');
-END $$;
-
--- ------------------------------------------------------------
--- 2. 设备状态(equipment_status)
---    T45-EQ-FL-CB 刻意缺失,用于验证回退逻辑
--- ------------------------------------------------------------
-INSERT INTO app_user.equipment_status
-    (equipment_id, current_status, alarm_status, online_status,
-     installation_addr, status_update_time, create_time, del_flag)
-VALUES
-    ('T45-EQ-PR-CN', 1, 1, 1, '城南大道1号', now() - interval '30 minutes', now() - interval '30 minutes', '0'),
-    ('T45-EQ-PR-CB', 1, 0, 1, '城北大道2号', now() - interval '1 hour',     now() - interval '1 hour',     '0'),
-    ('T45-EQ-FL-TC', 1, 1, 1, '太常路3号',   now() - interval '2 hours',    now() - interval '2 hours',    '0'),
-    ('T45-EQ-LK-CN', 1, 0, 0, '城南大道4号', now() - interval '3 hours',    now() - interval '3 hours',    '0');
-
--- ------------------------------------------------------------
--- 3. 阈值(warning_threshold)
---    t45-thr-004 下限为 0,用于验证“阈值下限为 0”不被当成未配置
--- ------------------------------------------------------------
-INSERT INTO app_user.warning_threshold
-    (id, device_code, warning_type, warning_code, min_value, max_value,
-     period_start, period_end, remark, create_time, update_time)
-VALUES
-    ('t45-thr-001', 'CN-GS-202609160001', '压力预警', 'T45-WARN-PRESSURE', 0.40, 0.80,
-     NULL, NULL, '#45测试-全天阈值', now(), now()),
-    ('t45-thr-002', 'CB-GS-202609160002', '压力预警', 'T45-WARN-PRESSURE', 0.35, 0.85,
-     NULL, NULL, '#45测试-全天阈值', now(), now()),
-    ('t45-thr-003', 'TC-GS-202609160003', '流量预警', 'T45-WARN-FLOW', 10.00, 100.00,
-     '08:00', '20:00', '#45测试-分时阈值(08:00-20:00)', now(), now()),
-    ('t45-thr-004', 'CN-GS-202609160004', '漏失预警', 'T45-WARN-LEAK', 0.00, 5.00,
-     NULL, NULL, '#45测试-阈值为0的边界', now(), now()),
-    ('t45-thr-005', 'CB-GS-202609160005', '流量预警', 'T45-WARN-FLOW', 8.00, 120.00,
-     NULL, NULL, '#45测试-全天阈值', now(), now());
-
--- ------------------------------------------------------------
--- 4. 报警流水(alarm_data)
---     alarm_status:0-未处理 1-已处理;alarm_level:1 最高
--- ------------------------------------------------------------
-INSERT INTO app_user.alarm_data
-    (id, device_code, device_name, device_type, warning_type, warning_code,
-     actual_value, min_value, max_value, alarm_status, alarm_level, deviation_ratio,
-     alarm_time, handle_time, handle_user, handle_remark, remark, create_time, update_time)
-VALUES
-    -- 今日:四个等级各一条,全部待审核(等级序列与展示状态的基础样本)
-    ('t45-alarm-001', 'CN-GS-202609160001', '城南加压站压力监测点', '压力监测', '压力预警', 'T45-WARN-PRESSURE',
-     0.95, 0.40, 0.80, 0, 1, 18.75, now() - interval '40 minutes', NULL, NULL, NULL,
-     '#45待审核-一级', now() - interval '40 minutes', now() - interval '40 minutes'),
-    ('t45-alarm-002', 'CB-GS-202609160002', '城北末梢压力监测点', '压力监测', '压力预警', 'T45-WARN-PRESSURE',
-     0.90, 0.35, 0.85, 0, 2, 5.88, now() - interval '35 minutes', NULL, NULL, NULL,
-     '#45待审核-二级', now() - interval '35 minutes', now() - interval '35 minutes'),
-    ('t45-alarm-003', 'TC-GS-202609160003', '太常厂区流量监测点', '流量监测', '流量预警', 'T45-WARN-FLOW',
-     112.00, 10.00, 100.00, 0, 3, 12.00, now() - interval '30 minutes', NULL, NULL, NULL,
-     '#45待审核-三级', now() - interval '30 minutes', now() - interval '30 minutes'),
-    ('t45-alarm-004', 'CN-GS-202609160004', '城南漏失声波监测点', '漏失监测', '漏失预警', 'T45-WARN-LEAK',
-     7.20, 0.00, 5.00, 0, 4, 44.00, now() - interval '25 minutes', NULL, NULL, NULL,
-     '#45待审核-四级(阈值下限为0)', now() - interval '25 minutes', now() - interval '25 minutes'),
-
-    -- 昨日:已转工单(关联未办结工单:处理中 / 待接单)
-    ('t45-alarm-005', 'TC-GS-202609160003', '太常厂区流量监测点', '流量监测', '流量预警', 'T45-WARN-FLOW',
-     130.50, 10.00, 100.00, 0, 1, 30.50, now() - interval '1 day' - interval '20 minutes',
-     NULL, NULL, NULL, '#45已转工单-处理中', now() - interval '1 day', now() - interval '1 day'),
-    ('t45-alarm-006', 'CN-GS-202609160001', '城南加压站压力监测点', '压力监测', '压力预警', 'T45-WARN-PRESSURE',
-     0.28, 0.40, 0.80, 0, 3, 30.00, now() - interval '1 day' - interval '10 minutes',
-     NULL, NULL, NULL, '#45已转工单-待接单', now() - interval '1 day', now() - interval '1 day'),
-
-    -- 前2日:已解除(报警记录已处理)+ 工单已结案不得算已转工单
-    ('t45-alarm-007', 'CB-GS-202609160002', '城北末梢压力监测点', '压力监测', '压力预警', 'T45-WARN-PRESSURE',
-     0.88, 0.35, 0.85, 1, 2, 3.53, now() - interval '2 days' - interval '30 minutes',
-     now() - interval '2 days', '李巡维', '压力恢复正常',
-     '#45已解除-已处理', now() - interval '2 days', now() - interval '2 days'),
-    ('t45-alarm-015', 'CN-GS-202609160004', '城南漏失声波监测点', '漏失监测', '漏失预警', 'T45-WARN-LEAK',
-     6.10, 0.00, 5.00, 0, 1, 22.00, now() - interval '2 days' - interval '15 minutes',
-     NULL, NULL, NULL, '#45工单已取消-应回到待审核', now() - interval '2 days', now() - interval '2 days'),
-
-    -- 前3日:误报解除(报警记录未处理,但审核结论为误报)
-    ('t45-alarm-008', 'CN-GS-202609160004', '城南漏失声波监测点', '漏失监测', '漏失预警', 'T45-WARN-LEAK',
-     5.40, 0.00, 5.00, 0, 1, 8.00, now() - interval '3 days' - interval '20 minutes',
-     NULL, NULL, NULL, '#45已解除-误报', now() - interval '3 days', now() - interval '3 days'),
-
-    -- 前4日:无 equipment_status 记录的设备(设备报警状态回退分支)
-    ('t45-alarm-012', 'CB-GS-202609160005', '城北出厂流量监测点', '流量监测', '流量预警', 'T45-WARN-FLOW',
-     3.20, 8.00, 120.00, 0, 4, 60.00, now() - interval '4 days' - interval '20 minutes',
-     NULL, NULL, NULL, '#45无设备状态记录-待审核', now() - interval '4 days', now() - interval '4 days'),
-
-    -- 前5日:报警值与阈值全为空(未配置阈值显示分支)
-    ('t45-alarm-013', 'CN-GS-202609160001', '城南加压站压力监测点', '压力监测', '压力预警', 'T45-WARN-PRESSURE',
-     NULL, NULL, NULL, 0, 3, NULL, now() - interval '5 days' - interval '20 minutes',
-     NULL, NULL, NULL, '#45阈值未配置', now() - interval '5 days', now() - interval '5 days'),
-
-    -- 前6日:趋势窗口首日,仍应出现在趋势里
-    ('t45-alarm-009', 'CN-GS-202609160004', '城南漏失声波监测点', '漏失监测', '漏失预警', 'T45-WARN-LEAK',
-     5.80, 0.00, 5.00, 1, 4, 16.00, now() - interval '6 days' - interval '20 minutes',
-     now() - interval '6 days', '赵巡维', '已现场核查',
-     '#45窗口边界-已解除', now() - interval '6 days', now() - interval '6 days'),
-
-    -- 窗口外:用于验证时间范围查询能把它们查出来、而 7 天趋势不含它们
-    ('t45-alarm-010', 'TC-GS-202609160003', '太常厂区流量监测点', '流量监测', '流量预警', 'T45-WARN-FLOW',
-     140.00, 10.00, 100.00, 0, 1, 40.00, now() - interval '9 days' - interval '20 minutes',
-     NULL, NULL, NULL, '#45窗口外-待审核', now() - interval '9 days', now() - interval '9 days'),
-    ('t45-alarm-011', 'CB-GS-202609160002', '城北末梢压力监测点', '压力监测', '压力预警', 'T45-WARN-PRESSURE',
-     0.30, 0.35, 0.85, 1, 2, 14.71, now() - interval '12 days' - interval '20 minutes',
-     now() - interval '12 days', '李巡维', '已换表处理',
-     '#45窗口外-已解除', now() - interval '12 days', now() - interval '12 days'),
-
-    -- 今日:阈值越界标红样本(下限 0、上限 120,实际 150)
-    ('t45-alarm-014', 'TC-GS-202609160003', '太常厂区流量监测点', '流量监测', '流量预警', 'T45-WARN-FLOW',
-     150.00, 0.00, 120.00, 0, 2, 25.00, now() - interval '5 minutes',
-     NULL, NULL, NULL, '#45待审核-阈值越界标红', now() - interval '5 minutes', now() - interval '5 minutes');
-
--- ------------------------------------------------------------
--- 5. 关联工单(work_order)
---    工单状态:0-待派单 1-待接单 2-已接单 3-处理中 4-待验收 5-已结案 6-延期中 7-已取消
---    仅未办结工单会让报警显示为“已转工单”
---
---    注意:工单流程重构后 work_order.order_type 已被 DROP(见
---    migration_work_order_status_refactor.sql),报警来源工单以 alarm_id 关联识别;
---    dispatch_user / receive_user / verify_user 均为 BIGINT 用户ID,不得写姓名。
---    本段只写入 WorkOrder 实体确证的列,避免依赖已废弃字段。
--- ------------------------------------------------------------
-INSERT INTO app_user.work_order
-    (order_no, alarm_id, device_id, device_code, order_level, order_desc,
-     dispatch_user, dispatch_time, receive_user, order_status,
-     fault_time, create_time, update_time)
-VALUES
-    -- 处理中:t45-alarm-005 → 已转工单,可验证“前往工单处置”跳转
-    ('T45-WO-001', 't45-alarm-005', 'T45-EQ-FL-TC', 'TC-GS-202609160003', 0,
-     '#45测试工单-太常流量超限处置', 1, now() - interval '22 hours', 2, 3,
-     now() - interval '1 day', now() - interval '1 day', now() - interval '1 day'),
-    -- 待接单:t45-alarm-006 → 已转工单
-    ('T45-WO-002', 't45-alarm-006', 'T45-EQ-PR-CN', 'CN-GS-202609160001', 1,
-     '#45测试工单-城南压力偏低待接单', 1, now() - interval '22 hours', NULL, 1,
-     now() - interval '1 day', now() - interval '1 day', now() - interval '1 day'),
-    -- 已取消:t45-alarm-015 关联已取消工单,报警不得算作已转工单
-    ('T45-WO-003', 't45-alarm-015', 'T45-EQ-LK-CN', 'CN-GS-202609160004', 1,
-     '#45测试工单-已取消应回到待审核', 1, now() - interval '2 days', NULL, 7,
-     now() - interval '2 days', now() - interval '2 days', now() - interval '2 days');
-
-INSERT INTO app_user.work_order_log
-    (order_id, oper_type, oper_desc, oper_user_id, oper_user_name, oper_time)
-SELECT order_id, 1, '#45测试-派单', 1, '调度管理员', now() - interval '22 hours'
-  FROM app_user.work_order WHERE order_no IN ('T45-WO-001', 'T45-WO-002');
-
--- ------------------------------------------------------------
--- 6. 报警审核记录(alarm_audit)
---    t45-alarm-008 审核结论=2(误报)→ 报警展示状态应为已解除
--- ------------------------------------------------------------
-INSERT INTO app_user.alarm_audit
-    (alarm_id, audit_action, audit_result, audit_opinion, attach_url,
-     audit_user_id, audit_user_name, audit_time, create_time, update_time)
-VALUES
-    ('t45-alarm-008', 2, 2, '#45测试审核:现场核实为误报,已解除', NULL,
-     1, '调度管理员', now() - interval '3 days', now() - interval '3 days', now() - interval '3 days'),
-    ('t45-alarm-007', 1, 1, '#45测试审核:报警属实,已处置完成', NULL,
-     1, '调度管理员', now() - interval '2 days', now() - interval '2 days', now() - interval '2 days');
-
--- ============================================================
--- 清理脚本(如需移除本批测试数据,执行以下语句)
--- ============================================================
--- DELETE FROM app_user.alarm_audit      WHERE alarm_id LIKE 't45-alarm-%';
--- DELETE FROM app_user.work_order_log   WHERE order_id IN
---     (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'T45-WO-%');
--- DELETE FROM app_user.work_order       WHERE order_no LIKE 'T45-WO-%' OR alarm_id LIKE 't45-alarm-%';
--- DELETE FROM app_user.alarm_data       WHERE id LIKE 't45-alarm-%';
--- DELETE FROM app_user.warning_threshold WHERE id LIKE 't45-thr-%' OR device_code LIKE 'T45-%';
--- DELETE FROM app_user.equipment_status WHERE equipment_id LIKE 'T45-EQ-%';
--- DELETE FROM app_user.equipment_base   WHERE equipment_id LIKE 'T45-EQ-%';

+ 0 - 145
pipe-network-service/sql/water_supply_device_test_data.sql

@@ -1,145 +0,0 @@
--- ============================================================
--- 供水管网 T6 设备准入、台账与异常态势 测试数据脚本(KingbaseES)
--- 说明:
---   1. 测试主键与编号均使用 T6-TEST- 前缀,可重复执行。
---   2. 本脚本只初始化测试数据,不创建业务表;执行前请确认以下表已存在:
---      app_user.equipment_type、app_user.equipment_base、app_user.equipment_status、
---      app_user.alarm_data、app_user.work_order
---   3. 覆盖场景:正常供水设备、报警供水设备、维修供水设备、离线供水设备、
---      非供水设备排除、有效报警原因、真实工单编号与状态。
--- ============================================================
-
--- ------------------------------------------------------------
--- 0. 清理历史测试数据(先清工单与报警,再清状态与设备,最后清临时类型)
--- ------------------------------------------------------------
-DELETE FROM app_user.work_order_log WHERE order_id IN
-    (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'T6-TEST-WO-%');
-DELETE FROM app_user.work_order WHERE order_no LIKE 'T6-TEST-WO-%';
-DELETE FROM app_user.alarm_data WHERE id LIKE 'T6-TEST-ALARM-%';
-DELETE FROM app_user.equipment_status WHERE equipment_id LIKE 'T6-TEST-EQ-%';
-DELETE FROM app_user.equipment_base WHERE equipment_id LIKE 'T6-TEST-EQ-%';
-DELETE FROM app_user.equipment_type WHERE id = 'T6-TEST-GAS-TYPE';
-
--- ------------------------------------------------------------
--- 1. 校验规范供水设备类型,并创建临时非供水类型用于边界排除
--- ------------------------------------------------------------
-DO $$
-DECLARE
-    v_count integer;
-BEGIN
-    SELECT count(*) INTO v_count
-      FROM app_user.equipment_type
-     WHERE id = '1' AND parent_type_id = '0' AND type_name = '供水';
-    IF v_count <> 1 THEN
-        RAISE EXCEPTION '缺少规范供水顶级设备类型:id=1,type_name=供水,parent_type_id=0';
-    END IF;
-
-    SELECT count(*) INTO v_count
-      FROM app_user.equipment_type
-     WHERE type_id IN ('ws_flow', 'ws_pressure', 'ws_leak')
-       AND parent_type_id = '1';
-    IF v_count <> 3 THEN
-        RAISE EXCEPTION '缺少规范供水监测子类型:ws_flow/ws_pressure/ws_leak 必须 parent_type_id=1';
-    END IF;
-END $$;
-
-INSERT INTO app_user.equipment_type
-    (id, type_id, type_name, parent_type_id, type_remark)
-VALUES
-    ('T6-TEST-GAS-TYPE', 't6_test_gas', '燃气(测试)', '0', 'T6非供水设备排除测试类型');
-
--- ------------------------------------------------------------
--- 2. 设备基础信息(4台供水设备 + 1台非供水设备)
--- ------------------------------------------------------------
-INSERT INTO app_user.equipment_base
-    (equipment_id, equipment_code, equipment_name, equipment_model, equipment_type_id,
-     longitude, latitude, equipment_location, maintainer, maintainer_phone,
-     ownership_unit, remark, create_time, update_time, del_flag, district)
-VALUES
-    ('T6-TEST-EQ-PRESSURE-ALARM', 'CN-GS-202609020001', 'T6测试压力报警设备', 'PRESSURE-T6',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1),
-     113.28000000, 23.12000000, 'T6测试大道1号', 'T6测试维护员', '13800000001',
-     'T6测试供水公司', 'T6设备准入与异常态势测试数据', now() - interval '7 days', now(), '0', '城南'),
-    ('T6-TEST-EQ-FLOW-REPAIR', 'CB-GS-202609020001', 'T6测试流量维修设备', 'FLOW-T6',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1),
-     113.29000000, 23.13000000, 'T6测试大道2号', 'T6测试维护员', '13800000002',
-     'T6测试供水公司', 'T6设备准入与异常态势测试数据', now() - interval '7 days', now(), '0', '城北'),
-    ('T6-TEST-EQ-LEAK-OFFLINE', 'TC-GS-202609020001', 'T6测试漏失离线设备', 'LEAK-T6',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_leak' AND parent_type_id = '1' LIMIT 1),
-     113.30000000, 23.14000000, 'T6测试大道3号', 'T6测试维护员', '13800000003',
-     'T6测试供水公司', 'T6设备准入与异常态势测试数据', now() - interval '7 days', now(), '0', '太常'),
-    ('T6-TEST-EQ-PRESSURE-NORMAL', 'CN-GS-202609020002', 'T6测试压力正常设备', 'PRESSURE-T6',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1),
-     113.31000000, 23.15000000, 'T6测试大道4号', 'T6测试维护员', '13800000004',
-     'T6测试供水公司', 'T6设备准入与异常态势测试数据', now() - interval '7 days', now(), '0', '城南'),
-    ('T6-TEST-EQ-GAS-EXCLUDED', 'CN-RQ-202609020001', 'T6测试燃气排除设备', 'GAS-T6',
-     'T6-TEST-GAS-TYPE', 113.32000000, 23.16000000, 'T6测试大道5号',
-     'T6测试维护员', '13800000005', 'T6测试燃气公司', 'T6非供水排除测试数据',
-     now() - interval '7 days', now(), '0', '城南');
-
--- ------------------------------------------------------------
--- 3. 设备状态(current_status / alarm_status / online_status 分别表达不同状态)
--- ------------------------------------------------------------
-INSERT INTO app_user.equipment_status
-    (equipment_id, current_status, alarm_status, online_status,
-     installation_addr, status_update_time, create_time, del_flag)
-VALUES
-    ('T6-TEST-EQ-PRESSURE-ALARM', 1, 1, 1, 'T6测试大道1号',
-     now() - interval '1 hour', now() - interval '1 hour', '0'),
-    ('T6-TEST-EQ-FLOW-REPAIR', 3, 0, 0, 'T6测试大道2号',
-     now() - interval '2 hours', now() - interval '2 hours', '0'),
-    ('T6-TEST-EQ-LEAK-OFFLINE', 1, 0, 0, 'T6测试大道3号',
-     now() - interval '3 hours', now() - interval '3 hours', '0'),
-    ('T6-TEST-EQ-PRESSURE-NORMAL', 1, 0, 1, 'T6测试大道4号',
-     now() - interval '4 hours', now() - interval '4 hours', '0'),
-    ('T6-TEST-EQ-GAS-EXCLUDED', 1, 1, 1, 'T6测试大道5号',
-     now() - interval '5 hours', now() - interval '5 hours', '0');
-
--- ------------------------------------------------------------
--- 4. 有效报警原因(供水报警设备 + 非供水排除设备)
--- ------------------------------------------------------------
-INSERT INTO app_user.alarm_data
-    (id, device_code, device_name, device_type, warning_type, warning_code,
-     min_value, max_value, actual_value, alarm_level, deviation_ratio,
-     alarm_status, alarm_time, handle_time, handle_user, handle_remark, remark,
-     create_time, update_time)
-VALUES
-    ('T6-TEST-ALARM-PRESSURE', 'CN-GS-202609020001', 'T6测试压力报警设备', '压力监测',
-     '供水压力超限', 'WARN-PRESSURE-T6', 0.20, 0.80, 1.20, 2, 50.00,
-     0, now() - interval '1 hour', NULL, NULL, NULL, 'T6设备异常态势测试数据',
-     now() - interval '1 hour', now() - interval '1 hour'),
-    ('T6-TEST-ALARM-GAS-EXCLUDED', 'CN-RQ-202609020001', 'T6测试燃气排除设备', '燃气监测',
-     '燃气浓度超限', 'WARN-GAS-T6', 0.00, 20.00, 45.00, 1, 125.00,
-     0, now() - interval '1 hour', NULL, NULL, NULL, 'T6非供水排除测试数据',
-     now() - interval '1 hour', now() - interval '1 hour');
-
--- ------------------------------------------------------------
--- 5. 关联统一工单(真实 order_no,不用随机 ID)
--- ------------------------------------------------------------
-INSERT INTO app_user.work_order
-    (order_no, alarm_id, case_id, case_no, device_id, device_code,
-     order_type, order_level, order_desc, dept_id, dispatch_user, dispatch_time,
-     receive_user, order_status, delayed_reason, delayed_deadline, plan_finish_time,
-     real_finish_time, repair_result, maintenance_before_img, maintenance_after_img,
-     verify_user, verify_time, create_time, update_time)
-VALUES
-    ('T6-TEST-WO-001', 'T6-TEST-ALARM-PRESSURE', NULL, NULL,
-     'T6-TEST-EQ-PRESSURE-ALARM', 'CN-GS-202609020001',
-     1, 2, 'T6供水压力超限故障维修', NULL, NULL, now() - interval '50 minutes',
-     '1', 4, NULL, NULL, now() + interval '1 day',
-     NULL, NULL, NULL, NULL, NULL, NULL, now() - interval '50 minutes', now()),
-    ('T6-TEST-WO-002', NULL, NULL, NULL,
-     'T6-TEST-EQ-FLOW-REPAIR', 'CB-GS-202609020001',
-     1, 2, 'T6供水流量设备维修', NULL, NULL, now() - interval '2 hours',
-     '2', 4, NULL, NULL, now() + interval '1 day',
-     NULL, NULL, NULL, NULL,
-     NULL, NULL, now() - interval '2 hours', now());
-
--- ============================================================
--- 快速核验:
---   1. 供水设备台账应包含 4 台 T6 供水设备,不包含 CN-RQ-202609020001。
---   2. 异常设备页应包含压力报警设备与流量维修设备;正常压力设备与漏失离线设备不进入异常页。
---   3. CN-GS-202609020001 的异常原因为“供水压力超限”,关联工单号为 T6-TEST-WO-001,状态为处理中。
---   4. CB-GS-202609020001 的异常原因为设备维修中,关联工单号为 T6-TEST-WO-002,状态为处理中。
---   5. CN-RQ-202609020001 属于燃气测试类型,任何供水页面均不应展示。
--- ============================================================

+ 494 - 0
pipe-network-service/sql/water_supply_monitoring_alarm_rebuild_test_data.sql

@@ -0,0 +1,494 @@
+-- ============================================================
+-- 供水监测设备与报警测试数据统一重建脚本(KingbaseES)
+-- 对应 Gogs #56 T05;统一取代下列 5 个已失效的种子脚本:
+--   water_supply_monitoring_test_data.sql / water_supply_device_test_data.sql /
+--   water_supply_abnormal_test_data.sql / water_supply_alarm_ledger_test_data.sql /
+--   water_supply_alarm_audit_test_data.sql
+--
+-- 背景:
+--   equipment_type 迁移后,供水子类型以库中现值为权威:
+--     ultrasonic_flowmeter(11) 超声波外夹流量计
+--     pressure_gauge(12)       压力计
+--     leak_monitor(14)         漏失在线监测仪
+--   旧脚本按已不存在的 ws_flow/ws_pressure/ws_leak 取类型(执行到一半即中断),
+--   或写入的报警引用了并不存在的设备,导致:运行监测三页空列表、设备台账类型错位、
+--   报警台账只剩少量能对上设备的记录。本脚本不新增任何设备类型,一律按 type_id + parent_type_id 取现有类型 id。
+--
+-- 用法与安全边界:
+--   1. 幂等,可重复执行;只写入 wrb- 前缀的测试数据与设备台账,不修改表结构、不删其它系统设备。
+--   2. 执行前请先导出快照:equipment_base / equipment_status / alarm_data / work_order /
+--      alarm_audit / warning_threshold / radar_data / telemetry_data / firefighting_pressure / noise_info。
+--   3. 本脚本只删除带测试前缀的失效供水测试设备(WRB-EQ-* / WS-TEST-EQ-* / T6-* / TEST-* /
+--      Z-TEST-*),以及 equipment_type_id 已指向不存在类型的脏数据设备;不带测试前缀的
+--      供水设备一律保留。删除清单可在执行前快照中追溯。
+--   4. 非供水设备按类型归位而非删除:燃气→3,排水→2,窨井→4。
+--
+-- 执行后可对照的口径(本轮已在库中复算):
+--   设备:供水设备 15 台(流量 6 / 压力 5 / 漏失 4),全部挂在真实子类型 11/12/14
+--   运行监测:流量 6 台、压力 5 台、漏失 4 台均有最新监测值
+--   报警流水:16 条(一级 4 / 二级 5 / 三级 3 / 四级 4;流量预警 7 / 压力预警 5 / 漏失预警 4)
+--     展示状态:待审核 7 / 已转工单 7 / 已解除 2
+--       (展示状态按最新后端规则推导:关联工单仅“已取消(7)”回落到报警事实,
+--         “已结案(5)”仍计为已转工单;唯一性判定则按终态 5/7 放行)
+--   工单:8 张,状态 0..7 各一张
+--     计数条:全部 8 / 待处理 2 / 处理中 3 / 待验收 1 / 已完成 2
+--   报警审核待办队列(展示状态=待审核):7 条
+-- ============================================================
+
+-- ------------------------------------------------------------
+-- 0. 前置断言:真实供水监测子类型必须存在(不新增类型)
+-- ------------------------------------------------------------
+DO $$
+DECLARE
+    v_flow     varchar(64);
+    v_pressure varchar(64);
+    v_leak     varchar(64);
+BEGIN
+    SELECT id INTO v_flow     FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1;
+    SELECT id INTO v_pressure FROM app_user.equipment_type WHERE type_id = 'pressure_gauge'        AND parent_type_id = '1' LIMIT 1;
+    SELECT id INTO v_leak     FROM app_user.equipment_type WHERE type_id = 'leak_monitor'          AND parent_type_id = '1' LIMIT 1;
+    IF v_flow IS NULL OR v_pressure IS NULL OR v_leak IS NULL THEN
+        RAISE EXCEPTION '供水监测子类型缺失:需要 ultrasonic_flowmeter / pressure_gauge / leak_monitor 且 parent_type_id=1;本脚本不新增设备类型';
+    END IF;
+END $$;
+
+-- ------------------------------------------------------------
+-- 1. 非供水设备归位:燃气→3、排水→2、窨井→4(不删除)
+-- ------------------------------------------------------------
+UPDATE app_user.equipment_base SET equipment_type_id = '3', update_time = now()
+ WHERE equipment_id IN ('TEST-STAT-IND-E-GAS',
+                        'c586610c5e77938c59df57dfdf64e1e8',
+                        '18f1adc653d1b051c7460aeeb567dcc4',
+                        '1649ee4fe3aeb2e83f80ddfac94a893b',
+                        'T6-ABN-TEST-EQ-GAS-EXCLUDED')
+   AND equipment_type_id <> '3';
+
+UPDATE app_user.equipment_base SET equipment_type_id = '2', update_time = now()
+ WHERE equipment_id IN ('TEST-STAT-IND-E-DRAIN', 'TEST-WS-DEV-001', 'TEST-WS-DEV-002')
+   AND equipment_type_id <> '2';
+
+UPDATE app_user.equipment_base SET equipment_type_id = '4', update_time = now()
+ WHERE equipment_id IN ('3b3bccd846af495cf99db762b312a059', 'dfbb32ef87a74fc353707c060c94f01c')
+   AND equipment_type_id <> '4';
+
+-- ------------------------------------------------------------
+-- 2. 圈定待删除的失效供水测试设备(含死引用脏数据)
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS wsr_deleted_devices;
+CREATE TEMP TABLE wsr_deleted_devices (equipment_id varchar(64), equipment_code varchar(64));
+
+INSERT INTO wsr_deleted_devices (equipment_id, equipment_code)
+SELECT equipment_id, equipment_code
+  FROM app_user.equipment_base
+ WHERE (equipment_type_id IN (SELECT id FROM app_user.equipment_type WHERE parent_type_id = '1')
+        AND (equipment_id LIKE 'WRB-EQ-%'
+             OR equipment_id LIKE 'WS-TEST-EQ-%'
+             OR equipment_id LIKE 'T6-%'
+             OR equipment_id LIKE 'TEST-%'
+             OR equipment_id LIKE 'Z-TEST-%'))
+    OR equipment_id IN ('WS-TEST-EQ-FLOW-004', 'WS-TEST-EQ-LEAKAGE')
+    OR equipment_id IN ('4417f88149637b52ed804c0590775830',
+                        'ad5e086344b5e33c670f0e2e6ca3b42c',
+                        'a54cf5adf4b74bfbda7c6a401892c10c',
+                        'f2e6f710375b55ed47c341f72971fb37',
+                        'ca86bcdb1bf090a84cc3bca5a3852b14',
+                        '310d7b467b29ce572c22ae555fd7bc70',
+                        'e1df0a29246c351cee6fdacd26211950',
+                        '1168a88f61954895916932409dd2c692',
+                        '3f70e8259b634705e271e524f225347b');
+
+-- ------------------------------------------------------------
+-- 3. 先清从属数据(外键与业务引用),再删设备
+-- ------------------------------------------------------------
+DELETE FROM app_user.alarm_audit
+ WHERE alarm_id IN (SELECT id FROM app_user.alarm_data
+                     WHERE device_code IN (SELECT equipment_code FROM wsr_deleted_devices));
+
+DELETE FROM app_user.work_order_log
+ WHERE order_id IN (SELECT order_id FROM app_user.work_order
+                     WHERE device_id IN (SELECT equipment_id FROM wsr_deleted_devices));
+
+DELETE FROM app_user.work_order
+ WHERE device_id IN (SELECT equipment_id FROM wsr_deleted_devices)
+    OR device_code IN (SELECT equipment_code FROM wsr_deleted_devices);
+
+DELETE FROM app_user.alarm_data
+ WHERE device_code IN (SELECT equipment_code FROM wsr_deleted_devices);
+
+DELETE FROM app_user.warning_threshold
+ WHERE device_code IN (SELECT equipment_code FROM wsr_deleted_devices);
+
+DELETE FROM app_user.radar_data            WHERE device_code           IN (SELECT equipment_code FROM wsr_deleted_devices);
+DELETE FROM app_user.telemetry_data        WHERE device_code           IN (SELECT equipment_code FROM wsr_deleted_devices);
+DELETE FROM app_user.firefighting_pressure WHERE telemetering_station  IN (SELECT equipment_code FROM wsr_deleted_devices);
+DELETE FROM app_user.noise_info            WHERE encode                IN (SELECT equipment_code FROM wsr_deleted_devices);
+DELETE FROM app_user.equipment_status      WHERE equipment_id          IN (SELECT equipment_id FROM wsr_deleted_devices);
+DELETE FROM app_user.equipment_maintain    WHERE equipment_id          IN (SELECT equipment_id FROM wsr_deleted_devices);
+DELETE FROM app_user.equipment_point_rel   WHERE equipment_id          IN (SELECT equipment_id FROM wsr_deleted_devices);
+DELETE FROM app_user.equipment_test        WHERE equipment_id          IN (SELECT equipment_id FROM wsr_deleted_devices);
+DELETE FROM app_user.equipment_base        WHERE equipment_id          IN (SELECT equipment_id FROM wsr_deleted_devices);
+
+-- ------------------------------------------------------------
+-- 4. 清掉被本脚本取代的报警/工单/审核/阈值测试数据
+-- ------------------------------------------------------------
+DELETE FROM app_user.alarm_audit
+ WHERE alarm_id LIKE 't45-alarm-%' OR alarm_id LIKE 't46-alarm-%' OR alarm_id LIKE 'wrb-alarm-%'
+    OR alarm_id IN ('test-alarm-004', 'test-alarm-005', 'test-alarm-006', 'test-alarm-007');
+
+DELETE FROM app_user.work_order_log
+ WHERE order_id IN (SELECT order_id FROM app_user.work_order
+                     WHERE order_no LIKE 'T45-WO-%' OR order_no LIKE 'T46-WO-%' OR order_no LIKE 'WRB-WO-%'
+                        OR alarm_id LIKE 't45-alarm-%' OR alarm_id LIKE 't46-alarm-%' OR alarm_id LIKE 'wrb-alarm-%');
+
+DELETE FROM app_user.work_order
+ WHERE order_no LIKE 'T45-WO-%' OR order_no LIKE 'T46-WO-%' OR order_no LIKE 'WRB-WO-%'
+    OR alarm_id LIKE 't45-alarm-%' OR alarm_id LIKE 't46-alarm-%' OR alarm_id LIKE 'wrb-alarm-%';
+
+DELETE FROM app_user.alarm_data
+ WHERE id LIKE 't45-alarm-%' OR id LIKE 't46-alarm-%' OR id LIKE 'wrb-alarm-%'
+    OR id IN ('test-alarm-004', 'test-alarm-005', 'test-alarm-006', 'test-alarm-007');
+
+DELETE FROM app_user.warning_threshold
+ WHERE id LIKE 't45-thr-%' OR id LIKE 't46-thr-%' OR id LIKE 'wrb-thr-%' OR device_code = 'TEST-PR-001';
+
+-- ------------------------------------------------------------
+-- 5. 供水监测设备(流量 6 / 压力 5 / 漏失 4,全部挂真实子类型)
+-- ------------------------------------------------------------
+INSERT INTO app_user.equipment_base
+    (equipment_id, equipment_code, equipment_name, equipment_model, equipment_type_id,
+     longitude, latitude, equipment_location, maintainer, maintainer_phone, ownership_unit,
+     remark, create_time, update_time, del_flag, district)
+VALUES
+    ('WRB-EQ-FL-01', 'CN-GS-202609160201', '城南主轴流量监测点', 'WRB-FL-1',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1),
+     113.28100000, 23.12100000, '城南大道201号', '张巡维', '13800000301', '市供水公司',
+     '#56统一重建-流量监测', now(), now(), '0', '城南'),
+    ('WRB-EQ-FL-02', 'CB-GS-202609160202', '城北出厂流量监测点', 'WRB-FL-2',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1),
+     113.31200000, 23.17200000, '城北大道202号', '李巡维', '13800000302', '市供水公司',
+     '#56统一重建-流量监测', now(), now(), '0', '城北'),
+    ('WRB-EQ-FL-03', 'TC-GS-202609160203', '太常厂区流量监测点', 'WRB-FL-3',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1),
+     113.25100000, 23.09100000, '太常路203号', '王巡维', '13800000303', '市供水公司',
+     '#56统一重建-流量监测', now(), now(), '0', '太常'),
+    ('WRB-EQ-FL-04', 'CN-GS-202609160204', '城南支线流量监测点', 'WRB-FL-4',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1),
+     113.28600000, 23.12600000, '城南大道204号', '赵巡维', '13800000304', '市供水公司',
+     '#56统一重建-流量监测', now(), now(), '0', '城南'),
+    ('WRB-EQ-FL-05', 'CB-GS-202609160205', '城北支线流量监测点', 'WRB-FL-5',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1),
+     113.31600000, 23.17600000, '城北大道205号', '孙巡维', '13800000305', '市供水公司',
+     '#56统一重建-流量监测', now(), now(), '0', '城北'),
+    ('WRB-EQ-FL-06', 'TC-GS-202609160206', '太常支线流量监测点', 'WRB-FL-6',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1),
+     113.25600000, 23.09600000, '太常路206号', '周巡维', '13800000306', '市供水公司',
+     '#56统一重建-无设备状态记录(报警状态回退分支)', now(), now(), '0', '太常'),
+    ('WRB-EQ-PR-01', 'CN-GS-202609160211', '城南加压站压力监测点', 'WRB-PR-1',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1),
+     113.28200000, 23.12200000, '城南大道211号', '张巡维', '13800000311', '市供水公司',
+     '#56统一重建-压力监测', now(), now(), '0', '城南'),
+    ('WRB-EQ-PR-02', 'CB-GS-202609160212', '城北末梢压力监测点', 'WRB-PR-2',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1),
+     113.31300000, 23.17300000, '城北大道212号', '李巡维', '13800000312', '市供水公司',
+     '#56统一重建-压力监测', now(), now(), '0', '城北'),
+    ('WRB-EQ-PR-03', 'TC-GS-202609160213', '太常主管压力监测点', 'WRB-PR-3',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1),
+     113.25200000, 23.09200000, '太常路213号', '王巡维', '13800000313', '市供水公司',
+     '#56统一重建-压力监测', now(), now(), '0', '太常'),
+    ('WRB-EQ-PR-04', 'CN-GS-202609160214', '城南小区入口压力监测点', 'WRB-PR-4',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1),
+     113.28700000, 23.12700000, '城南大道214号', '赵巡维', '13800000314', '市供水公司',
+     '#56统一重建-压力监测', now(), now(), '0', '城南'),
+    ('WRB-EQ-PR-05', 'CB-GS-202609160215', '城北高位水池压力监测点', 'WRB-PR-5',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1),
+     113.31700000, 23.17700000, '城北大道215号', '孙巡维', '13800000315', '市供水公司',
+     '#56统一重建-压力监测', now(), now(), '0', '城北'),
+    ('WRB-EQ-LK-01', 'CN-GS-202609160221', '城南漏失声波监测点', 'WRB-LK-1',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1),
+     113.28300000, 23.12300000, '城南大道221号', '张巡维', '13800000321', '市供水公司',
+     '#56统一重建-漏失监测', now(), now(), '0', '城南'),
+    ('WRB-EQ-LK-02', 'CB-GS-202609160222', '城北漏失声波监测点', 'WRB-LK-2',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1),
+     113.31400000, 23.17400000, '城北大道222号', '李巡维', '13800000322', '市供水公司',
+     '#56统一重建-漏失监测', now(), now(), '0', '城北'),
+    ('WRB-EQ-LK-03', 'TC-GS-202609160223', '太常漏失声波监测点', 'WRB-LK-3',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1),
+     113.25300000, 23.09300000, '太常路223号', '王巡维', '13800000323', '市供水公司',
+     '#56统一重建-漏失监测', now(), now(), '0', '太常'),
+    ('WRB-EQ-LK-04', 'CN-GS-202609160224', '城南老城区漏失监测点', 'WRB-LK-4',
+     (SELECT id FROM app_user.equipment_type WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1),
+     113.28800000, 23.12800000, '城南大道224号', '赵巡维', '13800000324', '市供水公司',
+     '#56统一重建-漏失监测', now(), now(), '0', '城南');
+
+-- ------------------------------------------------------------
+-- 6. 设备状态(WRB-EQ-FL-06 刻意缺失,用于验证报警状态回退分支)
+-- ------------------------------------------------------------
+INSERT INTO app_user.equipment_status
+    (equipment_id, current_status, alarm_status, online_status,
+     installation_addr, status_update_time, create_time, del_flag)
+VALUES
+    ('WRB-EQ-FL-01', 1, 1, 1, '城南大道201号', now() - interval '20 minutes', now() - interval '20 minutes', '0'),
+    ('WRB-EQ-FL-02', 1, 0, 1, '城北大道202号', now() - interval '30 minutes', now() - interval '30 minutes', '0'),
+    ('WRB-EQ-FL-03', 1, 0, 1, '太常路203号',   now() - interval '40 minutes', now() - interval '40 minutes', '0'),
+    ('WRB-EQ-FL-04', 1, 0, 1, '城南大道204号', now() - interval '1 hour',     now() - interval '1 hour',     '0'),
+    ('WRB-EQ-FL-05', 1, 0, 0, '城北大道205号', now() - interval '2 hours',    now() - interval '2 hours',    '0'),
+    ('WRB-EQ-PR-01', 1, 1, 1, '城南大道211号', now() - interval '20 minutes', now() - interval '20 minutes', '0'),
+    ('WRB-EQ-PR-02', 1, 0, 1, '城北大道212号', now() - interval '30 minutes', now() - interval '30 minutes', '0'),
+    ('WRB-EQ-PR-03', 1, 0, 1, '太常路213号',   now() - interval '40 minutes', now() - interval '40 minutes', '0'),
+    ('WRB-EQ-PR-04', 1, 0, 1, '城南大道214号', now() - interval '1 hour',     now() - interval '1 hour',     '0'),
+    ('WRB-EQ-PR-05', 1, 0, 1, '城北大道215号', now() - interval '2 hours',    now() - interval '2 hours',    '0'),
+    ('WRB-EQ-LK-01', 1, 1, 1, '城南大道221号', now() - interval '20 minutes', now() - interval '20 minutes', '0'),
+    ('WRB-EQ-LK-02', 1, 0, 1, '城北大道222号', now() - interval '30 minutes', now() - interval '30 minutes', '0'),
+    ('WRB-EQ-LK-03', 1, 0, 1, '太常路223号',   now() - interval '40 minutes', now() - interval '40 minutes', '0'),
+    ('WRB-EQ-LK-04', 1, 0, 1, '城南大道224号', now() - interval '1 hour',     now() - interval '1 hour',     '0');
+
+-- ------------------------------------------------------------
+-- 7. 阈值(含分时阈值与下限为 0 的边界样本)
+-- ------------------------------------------------------------
+INSERT INTO app_user.warning_threshold
+    (id, device_code, warning_type, warning_code, min_value, max_value,
+     period_start, period_end, remark, create_time, update_time)
+VALUES
+    ('wrb-thr-01', 'CN-GS-202609160211', '压力预警', 'WRB-WARN-PRESSURE', 0.40, 0.80, NULL, NULL, '#56测试-全天阈值', now(), now()),
+    ('wrb-thr-02', 'CB-GS-202609160212', '压力预警', 'WRB-WARN-PRESSURE', 0.35, 0.85, NULL, NULL, '#56测试-全天阈值', now(), now()),
+    ('wrb-thr-03', 'CN-GS-202609160201', '流量预警', 'WRB-WARN-FLOW', 10.00, 100.00, '08:00', '20:00', '#56测试-分时阈值(08:00-20:00)', now(), now()),
+    ('wrb-thr-04', 'CB-GS-202609160202', '流量预警', 'WRB-WARN-FLOW', 8.00, 120.00, NULL, NULL, '#56测试-全天阈值', now(), now()),
+    ('wrb-thr-05', 'CN-GS-202609160221', '漏失预警', 'WRB-WARN-LEAK', 0.00, 5.00, NULL, NULL, '#56测试-阈值下限为0的边界', now(), now()),
+    ('wrb-thr-06', 'CB-GS-202609160222', '漏失预警', 'WRB-WARN-LEAK', 0.00, 6.00, NULL, NULL, '#56测试-全天阈值', now(), now());
+
+-- ------------------------------------------------------------
+-- 8. 运行监测测量值(流量走雷达/遥测,压力走消防压力,漏失走噪声)
+-- ------------------------------------------------------------
+INSERT INTO app_user.radar_data
+    (id, system_identifier, device_code, meter1_instant_flow, flow_speed, create_time)
+VALUES
+    ('wrb-radar-0101', 'WRB-SYSTEM', 'CN-GS-202609160201', '62', '1.85', now() - interval '1 hour'),
+    ('wrb-radar-0102', 'WRB-SYSTEM', 'CN-GS-202609160201', '58', '1.75', now() - interval '4 hours'),
+    ('wrb-radar-0103', 'WRB-SYSTEM', 'CN-GS-202609160201', '55', '1.70', now() - interval '8 hours'),
+    ('wrb-radar-0301', 'WRB-SYSTEM', 'TC-GS-202609160203', '48', '1.45', now() - interval '2 hours'),
+    ('wrb-radar-0302', 'WRB-SYSTEM', 'TC-GS-202609160203', '45', '1.40', now() - interval '6 hours'),
+    ('wrb-radar-0303', 'WRB-SYSTEM', 'TC-GS-202609160203', '42', '1.30', now() - interval '10 hours'),
+    ('wrb-radar-0501', 'WRB-SYSTEM', 'CB-GS-202609160205', '36', '1.10', now() - interval '3 hours'),
+    ('wrb-radar-0502', 'WRB-SYSTEM', 'CB-GS-202609160205', '33', '1.05', now() - interval '7 hours'),
+    ('wrb-radar-0503', 'WRB-SYSTEM', 'CB-GS-202609160205', '30', '1.00', now() - interval '12 hours');
+
+INSERT INTO app_user.telemetry_data
+    (id, system_identifier, device_code, meter1_instant_flow, meter1_positive_total,
+     flow_speed, temperature, create_time)
+VALUES
+    ('wrb-telemetry-0201', 'WRB-SYSTEM', 'CB-GS-202609160202', '74', '20481', '2.10', '24.60', now() - interval '1 hour'),
+    ('wrb-telemetry-0202', 'WRB-SYSTEM', 'CB-GS-202609160202', '70', '20390', '2.00', '24.40', now() - interval '5 hours'),
+    ('wrb-telemetry-0203', 'WRB-SYSTEM', 'CB-GS-202609160202', '68', '20300', '1.95', '24.10', now() - interval '9 hours'),
+    ('wrb-telemetry-0401', 'WRB-SYSTEM', 'CN-GS-202609160204', '41', '15260', '1.25', '24.20', now() - interval '2 hours'),
+    ('wrb-telemetry-0402', 'WRB-SYSTEM', 'CN-GS-202609160204', '39', '15180', '1.20', '24.00', now() - interval '6 hours'),
+    ('wrb-telemetry-0403', 'WRB-SYSTEM', 'CN-GS-202609160204', '37', '15100', '1.15', '23.80', now() - interval '11 hours'),
+    ('wrb-telemetry-0601', 'WRB-SYSTEM', 'TC-GS-202609160206', '27', '12040', '0.95', '23.90', now() - interval '3 hours'),
+    ('wrb-telemetry-0602', 'WRB-SYSTEM', 'TC-GS-202609160206', '25', '11990', '0.90', '23.70', now() - interval '7 hours'),
+    ('wrb-telemetry-0603', 'WRB-SYSTEM', 'TC-GS-202609160206', '23', '11940', '0.85', '23.50', now() - interval '13 hours');
+
+INSERT INTO app_user.firefighting_pressure
+    (id, central_station, telemetering_station, sending_time, observed_time,
+     pressure_value, create_time)
+VALUES
+    ('wrb-pressure-1101', 'WRB-CENTER', 'CN-GS-202609160211', now() - interval '1 hour', now() - interval '1 hour', 0.95, now() - interval '1 hour'),
+    ('wrb-pressure-1102', 'WRB-CENTER', 'CN-GS-202609160211', now() - interval '4 hours', now() - interval '4 hours', 0.88, now() - interval '4 hours'),
+    ('wrb-pressure-1103', 'WRB-CENTER', 'CN-GS-202609160211', now() - interval '9 hours', now() - interval '9 hours', 0.82, now() - interval '9 hours'),
+    ('wrb-pressure-1201', 'WRB-CENTER', 'CB-GS-202609160212', now() - interval '1 hour', now() - interval '1 hour', 0.30, now() - interval '1 hour'),
+    ('wrb-pressure-1202', 'WRB-CENTER', 'CB-GS-202609160212', now() - interval '5 hours', now() - interval '5 hours', 0.36, now() - interval '5 hours'),
+    ('wrb-pressure-1203', 'WRB-CENTER', 'CB-GS-202609160212', now() - interval '10 hours', now() - interval '10 hours', 0.42, now() - interval '10 hours'),
+    ('wrb-pressure-1301', 'WRB-CENTER', 'TC-GS-202609160213', now() - interval '2 hours', now() - interval '2 hours', 0.90, now() - interval '2 hours'),
+    ('wrb-pressure-1302', 'WRB-CENTER', 'TC-GS-202609160213', now() - interval '6 hours', now() - interval '6 hours', 0.86, now() - interval '6 hours'),
+    ('wrb-pressure-1303', 'WRB-CENTER', 'TC-GS-202609160213', now() - interval '12 hours', now() - interval '12 hours', 0.84, now() - interval '12 hours'),
+    ('wrb-pressure-1401', 'WRB-CENTER', 'CN-GS-202609160214', now() - interval '2 hours', now() - interval '2 hours', 0.62, now() - interval '2 hours'),
+    ('wrb-pressure-1402', 'WRB-CENTER', 'CN-GS-202609160214', now() - interval '7 hours', now() - interval '7 hours', 0.60, now() - interval '7 hours'),
+    ('wrb-pressure-1403', 'WRB-CENTER', 'CN-GS-202609160214', now() - interval '13 hours', now() - interval '13 hours', 0.58, now() - interval '13 hours'),
+    ('wrb-pressure-1501', 'WRB-CENTER', 'CB-GS-202609160215', now() - interval '3 hours', now() - interval '3 hours', 0.45, now() - interval '3 hours'),
+    ('wrb-pressure-1502', 'WRB-CENTER', 'CB-GS-202609160215', now() - interval '8 hours', now() - interval '8 hours', 0.44, now() - interval '8 hours'),
+    ('wrb-pressure-1503', 'WRB-CENTER', 'CB-GS-202609160215', now() - interval '14 hours', now() - interval '14 hours', 0.43, now() - interval '14 hours');
+
+INSERT INTO app_user.noise_info
+    (encode, power, gain, rms, center_frequency, ts, create_time, update_time)
+VALUES
+    ('CN-GS-202609160221', 12.00, 2.00, 120, 800.00, to_char(now() - interval '1 hour', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '1 hour', now() - interval '1 hour'),
+    ('CN-GS-202609160221', 9.00,  2.00, 100, 780.00, to_char(now() - interval '5 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '5 hours', now() - interval '5 hours'),
+    ('CN-GS-202609160221', 6.00,  1.50,  85, 760.00, to_char(now() - interval '10 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '10 hours', now() - interval '10 hours'),
+    ('CB-GS-202609160222', 15.00, 2.50, 125, 820.00, to_char(now() - interval '2 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '2 hours', now() - interval '2 hours'),
+    ('CB-GS-202609160222', 11.00, 2.00, 110, 800.00, to_char(now() - interval '6 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '6 hours', now() - interval '6 hours'),
+    ('CB-GS-202609160222', 8.00,  1.50,  95, 770.00, to_char(now() - interval '12 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '12 hours', now() - interval '12 hours'),
+    ('TC-GS-202609160223', 10.00, 2.00, 105, 790.00, to_char(now() - interval '3 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '3 hours', now() - interval '3 hours'),
+    ('TC-GS-202609160223', 7.00,  1.50,  90,  765.00, to_char(now() - interval '8 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '8 hours', now() - interval '8 hours'),
+    ('TC-GS-202609160223', 4.00,  1.00,  70,  700.00, to_char(now() - interval '15 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '15 hours', now() - interval '15 hours'),
+    ('CN-GS-202609160224', 13.00, 2.20, 118, 810.00, to_char(now() - interval '4 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '4 hours', now() - interval '4 hours'),
+    ('CN-GS-202609160224', 9.50,  2.00, 100, 785.00, to_char(now() - interval '9 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '9 hours', now() - interval '9 hours'),
+    ('CN-GS-202609160224', 5.50,  1.20,  80,  720.00, to_char(now() - interval '16 hours', 'YYYY-MM-DD HH24:MI:SS'), now() - interval '16 hours', now() - interval '16 hours');
+
+-- ------------------------------------------------------------
+-- 9. 报警流水(16 条:一级4/二级5/三级3/四级4;待审核8/已转工单6/已解除2)
+-- ------------------------------------------------------------
+INSERT INTO app_user.alarm_data
+    (id, device_name, device_code, device_type, warning_type, warning_code,
+     actual_value, min_value, max_value, alarm_status, alarm_level, deviation_ratio,
+     alarm_time, handle_time, handle_user, handle_remark, remark, create_time, update_time)
+VALUES
+    ('wrb-alarm-01', '城南主轴流量监测点', 'CN-GS-202609160201', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     132.00, 10.00, 100.00, 0, 1, 32.00, now() - interval '35 minutes', NULL, NULL, NULL,
+     '#56已转工单-WO-01 待派单', now(), now()),
+    ('wrb-alarm-02', '城北出厂流量监测点', 'CB-GS-202609160202', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     128.00, 8.00, 120.00, 0, 2, 6.67, now() - interval '3 hours', NULL, NULL, NULL,
+     '#56已转工单-WO-02 待接单', now(), now()),
+    ('wrb-alarm-03', '太常厂区流量监测点', 'TC-GS-202609160203', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     145.00, 10.00, 100.00, 0, 3, 45.00, now() - interval '1 day 2 hours', NULL, NULL, NULL,
+     '#56已转工单-WO-03 已接单', now(), now()),
+    ('wrb-alarm-04', '城南支线流量监测点', 'CN-GS-202609160204', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     118.00, 10.00, 100.00, 0, 4, 18.00, now() - interval '2 days', NULL, NULL, NULL,
+     '#56已转工单-WO-04 处理中', now(), now()),
+    ('wrb-alarm-05', '城南加压站压力监测点', 'CN-GS-202609160211', '压力监测', '压力预警', 'WRB-WARN-PRESSURE',
+     0.95, 0.40, 0.80, 0, 1, 18.75, now() - interval '3 days', NULL, NULL, NULL,
+     '#56已转工单-WO-05 待验收', now(), now()),
+    ('wrb-alarm-06', '城北末梢压力监测点', 'CB-GS-202609160212', '压力监测', '压力预警', 'WRB-WARN-PRESSURE',
+     0.30, 0.35, 0.85, 0, 2, 14.29, now() - interval '4 days', NULL, NULL, NULL,
+     '#56已转工单(WO-06 已结案);终态不占用唯一性名额,可再次转工单', now(), now()),
+    ('wrb-alarm-07', '城南漏失声波监测点', 'CN-GS-202609160221', '漏失监测', '漏失预警', 'WRB-WARN-LEAK',
+     7.20, 0.00, 5.00, 0, 3, 44.00, now() - interval '5 days', NULL, NULL, NULL,
+     '#56已转工单-WO-07 延期中', now(), now()),
+    ('wrb-alarm-08', '城北漏失声波监测点', 'CB-GS-202609160222', '漏失监测', '漏失预警', 'WRB-WARN-LEAK',
+     6.10, 0.00, 6.00, 0, 4, 1.67, now() - interval '6 days', NULL, NULL, NULL,
+     '#56待审核(WO-08 已取消,口径回落到报警事实);终态不占用唯一性名额', now(), now()),
+    ('wrb-alarm-09', '太常主管压力监测点', 'TC-GS-202609160213', '压力监测', '压力预警', 'WRB-WARN-PRESSURE',
+     0.28, 0.40, 0.80, 0, 1, 30.00, now() - interval '50 minutes', NULL, NULL, NULL,
+     '#56待审核-无工单,可直接转工单', now(), now()),
+    ('wrb-alarm-10', '城南小区入口压力监测点', 'CN-GS-202609160214', '压力监测', '压力预警', 'WRB-WARN-PRESSURE',
+     0.22, 0.40, 0.80, 0, 3, 45.00, now() - interval '5 hours', NULL, NULL, NULL,
+     '#56待审核-无工单,可直接转工单', now(), now()),
+    ('wrb-alarm-11', '太常漏失声波监测点', 'TC-GS-202609160223', '漏失监测', '漏失预警', 'WRB-WARN-LEAK',
+     9.40, 0.00, 5.00, 0, 2, 88.00, now() - interval '1 day 6 hours', NULL, NULL, NULL,
+     '#56待审核-无工单,可直接转工单', now(), now()),
+    ('wrb-alarm-12', '城北支线流量监测点', 'CB-GS-202609160205', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     155.00, 8.00, 120.00, 0, 4, 29.17, now() - interval '2 days 4 hours', NULL, NULL, NULL,
+     '#56待审核-无工单,可直接转工单', now(), now()),
+    ('wrb-alarm-13', '太常支线流量监测点', 'TC-GS-202609160206', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     112.00, 10.00, 100.00, 0, 2, 12.00, now() - interval '3 days 3 hours', NULL, NULL, NULL,
+     '#56待审核-设备无状态记录,报警状态走回退分支', now(), now()),
+    ('wrb-alarm-14', '城北高位水池压力监测点', 'CB-GS-202609160215', '压力监测', '压力预警', 'WRB-WARN-PRESSURE',
+     0.20, 0.40, 0.80, 0, 4, 50.00, now() - interval '4 days 5 hours', NULL, NULL, NULL,
+     '#56已解除-误报(审核结论=2,不产生工单)', now(), now()),
+    ('wrb-alarm-15', '城南老城区漏失监测点', 'CN-GS-202609160224', '漏失监测', '漏失预警', 'WRB-WARN-LEAK',
+     8.10, 0.00, 5.00, 1, 1, 62.00, now() - interval '6 days 2 hours',
+     now() - interval '6 days 1 hour', '刘昊林', '#56已解除-现场确认后人工处置', '#56已解除-报警记录已处理', now(), now()),
+    ('wrb-alarm-16', '城南主轴流量监测点', 'CN-GS-202609160201', '流量监测', '流量预警', 'WRB-WARN-FLOW',
+     124.00, 10.00, 100.00, 0, 2, 24.00, now() - interval '90 minutes', NULL, NULL, NULL,
+     '#56待审核-同设备同类型已有 WO-01 未办结,转工单应被阻止', now(), now());
+
+-- ------------------------------------------------------------
+-- 10. 工单(0..7 各一张;device_id 必须是供水设备 equipment_id,否则审核计数条取不到)
+-- ------------------------------------------------------------
+INSERT INTO app_user.work_order
+    (order_no, alarm_id, device_id, device_code, order_level, order_desc, dept_id,
+     dispatch_user, dispatch_time, receive_user, order_status, fault_time, create_time, update_time)
+VALUES
+    ('WRB-WO-01', 'wrb-alarm-01', 'WRB-EQ-FL-01', 'CN-GS-202609160201', 0,
+     '#56测试工单-城南主轴流量超限待派单', 100, NULL, NULL, NULL, 0, now() - interval '35 minutes', now(), now()),
+    ('WRB-WO-02', 'wrb-alarm-02', 'WRB-EQ-FL-02', 'CB-GS-202609160202', 1,
+     '#56测试工单-城北出厂流量超限待接单', 100, 1, now() - interval '3 hours', NULL, 1, now() - interval '3 hours', now(), now()),
+    ('WRB-WO-03', 'wrb-alarm-03', 'WRB-EQ-FL-03', 'TC-GS-202609160203', 0,
+     '#56测试工单-太常厂区流量超限已接单', 100, 1, now() - interval '1 day', 2, 2, now() - interval '1 day 2 hours', now(), now()),
+    ('WRB-WO-04', 'wrb-alarm-04', 'WRB-EQ-FL-04', 'CN-GS-202609160204', 1,
+     '#56测试工单-城南支线流量超限处理中', 100, 1, now() - interval '2 days', 2, 3, now() - interval '2 days', now(), now()),
+    ('WRB-WO-05', 'wrb-alarm-05', 'WRB-EQ-PR-01', 'CN-GS-202609160211', 1,
+     '#56测试工单-城南加压站压力超限待验收', 100, 1, now() - interval '3 days', 2, 4, now() - interval '3 days', now(), now()),
+    ('WRB-WO-06', 'wrb-alarm-06', 'WRB-EQ-PR-02', 'CB-GS-202609160212', 0,
+     '#56测试工单-城北末梢压力偏低已结案', 100, 1, now() - interval '4 days', 2, 5, now() - interval '4 days', now(), now()),
+    ('WRB-WO-07', 'wrb-alarm-07', 'WRB-EQ-LK-01', 'CN-GS-202609160221', 1,
+     '#56测试工单-城南漏失延期中', 100, 1, now() - interval '5 days', 2, 6, now() - interval '5 days', now(), now()),
+    ('WRB-WO-08', 'wrb-alarm-08', 'WRB-EQ-LK-02', 'CB-GS-202609160222', 0,
+     '#56测试工单-城北漏失已取消', 100, 1, now() - interval '6 days', NULL, 7, now() - interval '6 days', now(), now());
+
+INSERT INTO app_user.work_order_log
+    (order_id, oper_type, oper_desc, oper_user_id, oper_user_name, oper_time)
+SELECT order_id, 0, '#56测试-报警审核转工单创建', 1, '调度管理员', now()
+  FROM app_user.work_order
+ WHERE order_no LIKE 'WRB-WO-%';
+
+-- ------------------------------------------------------------
+-- 11. 报警审核记录(含误报解除样本)
+-- ------------------------------------------------------------
+INSERT INTO app_user.alarm_audit
+    (alarm_id, audit_action, audit_result, audit_opinion, attach_url,
+     audit_user_id, audit_user_name, audit_time, create_time, update_time)
+VALUES
+    ('wrb-alarm-01', 1, 1, '#56测试审核:流量超限属实,转故障维修工单', NULL, 1, '调度管理员', now() - interval '35 minutes', now(), now()),
+    ('wrb-alarm-03', 1, 1, '#56测试审核:流量超限属实,转故障维修工单', NULL, 1, '调度管理员', now() - interval '1 day 2 hours', now(), now()),
+    ('wrb-alarm-14', 2, 2, '#56测试审核:现场核实为误报,解除报警且不生成工单',
+     'https://example.com/wrb-false-alarm-evidence.jpg', 1, '调度管理员', now() - interval '4 days 5 hours', now(), now());
+
+-- ------------------------------------------------------------
+-- 12. 执行后自检(结果应与文件头口径一致)
+-- ------------------------------------------------------------
+SELECT '供水设备' AS item, count(*)::varchar AS value
+  FROM app_user.equipment_base
+ WHERE equipment_type_id IN (SELECT id FROM app_user.equipment_type WHERE parent_type_id = '1');
+SELECT '运行监测-流量' AS item, count(*)::varchar AS value
+  FROM app_user.equipment_base e
+ WHERE e.equipment_type_id = (SELECT id FROM app_user.equipment_type WHERE type_id = 'ultrasonic_flowmeter' AND parent_type_id = '1' LIMIT 1)
+   AND (EXISTS (SELECT 1 FROM app_user.radar_data r WHERE r.device_code = e.equipment_code)
+        OR EXISTS (SELECT 1 FROM app_user.telemetry_data t WHERE t.device_code = e.equipment_code))
+UNION ALL
+SELECT '运行监测-压力', count(DISTINCT e.equipment_code)::varchar
+  FROM app_user.equipment_base e
+  JOIN app_user.firefighting_pressure p ON p.telemetering_station = e.equipment_code
+ WHERE e.equipment_type_id = (SELECT id FROM app_user.equipment_type WHERE type_id = 'pressure_gauge' AND parent_type_id = '1' LIMIT 1)
+UNION ALL
+SELECT '运行监测-漏失', count(DISTINCT e.equipment_code)::varchar
+  FROM app_user.equipment_base e
+  JOIN app_user.noise_info n ON n.encode = e.equipment_code
+ WHERE e.equipment_type_id = (SELECT id FROM app_user.equipment_type WHERE type_id = 'leak_monitor' AND parent_type_id = '1' LIMIT 1);
+SELECT '报警-等级分布' AS item, string_agg(concat(lv::varchar, '级=', cnt::varchar), ' / ' ORDER BY lv) AS value
+  FROM (SELECT alarm_level lv, count(*) cnt FROM app_user.alarm_data WHERE id LIKE 'wrb-alarm-%' GROUP BY alarm_level) t;
+SELECT '报警-类型分布' AS item, string_agg(concat(warning_type, '=', cnt::varchar), ' / ' ORDER BY warning_type) AS value
+  FROM (SELECT warning_type, count(*) cnt FROM app_user.alarm_data WHERE id LIKE 'wrb-alarm-%' GROUP BY warning_type) t;
+SELECT '报警-展示状态' AS item, string_agg(concat(display_status, '=', cnt::varchar), ' / ' ORDER BY display_status) AS value
+  FROM (
+    SELECT CASE
+             WHEN EXISTS (SELECT 1 FROM app_user.work_order w
+                           WHERE w.alarm_id = a.id AND w.order_status <> 7) THEN '已转工单'
+             WHEN a.alarm_status = 1
+               OR EXISTS (SELECT 1 FROM app_user.alarm_audit au
+                           WHERE au.alarm_id = a.id AND au.audit_result = 2) THEN '已解除'
+             ELSE '待审核'
+           END AS display_status,
+           count(*) cnt
+      FROM app_user.alarm_data a
+     WHERE a.id LIKE 'wrb-alarm-%'
+     GROUP BY 1
+  ) t;
+SELECT '工单-状态分布' AS item, string_agg(concat(order_status::varchar, '=', cnt::varchar), ' / ' ORDER BY order_status) AS value
+  FROM (SELECT order_status, count(*) cnt FROM app_user.work_order WHERE order_no LIKE 'WRB-WO-%' GROUP BY order_status) t;
+SELECT '死引用设备' AS item, count(*)::varchar AS value
+  FROM app_user.equipment_base eb
+ WHERE eb.equipment_type_id IS NOT NULL
+   AND NOT EXISTS (SELECT 1 FROM app_user.equipment_type et WHERE et.id = eb.equipment_type_id);
+SELECT '供水设备缺测量值' AS item, count(*)::varchar AS value
+  FROM app_user.equipment_base e
+ WHERE e.equipment_type_id IN (SELECT id FROM app_user.equipment_type
+                                WHERE parent_type_id = '1'
+                                  AND type_id IN ('ultrasonic_flowmeter', 'pressure_gauge', 'leak_monitor'))
+   AND NOT EXISTS (SELECT 1 FROM app_user.radar_data r WHERE r.device_code = e.equipment_code)
+   AND NOT EXISTS (SELECT 1 FROM app_user.telemetry_data t WHERE t.device_code = e.equipment_code)
+   AND NOT EXISTS (SELECT 1 FROM app_user.firefighting_pressure p WHERE p.telemetering_station = e.equipment_code)
+   AND NOT EXISTS (SELECT 1 FROM app_user.noise_info n WHERE n.encode = e.equipment_code);
+
+-- ------------------------------------------------------------
+-- 清理脚本(如需移除本批测试数据,执行以下语句)
+-- ------------------------------------------------------------
+-- DELETE FROM app_user.alarm_audit     WHERE alarm_id LIKE 'wrb-alarm-%';
+-- DELETE FROM app_user.work_order_log  WHERE order_id IN
+--     (SELECT order_id FROM app_user.work_order WHERE order_no LIKE 'WRB-WO-%');
+-- DELETE FROM app_user.work_order      WHERE order_no LIKE 'WRB-WO-%' OR alarm_id LIKE 'wrb-alarm-%';
+-- DELETE FROM app_user.alarm_data      WHERE id LIKE 'wrb-alarm-%';
+-- DELETE FROM app_user.warning_threshold WHERE id LIKE 'wrb-thr-%' OR device_code LIKE '%20260916%';
+-- DELETE FROM app_user.radar_data            WHERE id LIKE 'wrb-%';
+-- DELETE FROM app_user.telemetry_data        WHERE id LIKE 'wrb-%';
+-- DELETE FROM app_user.firefighting_pressure WHERE id LIKE 'wrb-%';
+-- DELETE FROM app_user.noise_info            WHERE create_time > now() - interval '1 day' AND encode LIKE '%-20260916%';
+-- DELETE FROM app_user.equipment_status      WHERE equipment_id LIKE 'WRB-EQ-%';
+-- DELETE FROM app_user.equipment_base        WHERE equipment_id LIKE 'WRB-EQ-%';

+ 0 - 240
pipe-network-service/sql/water_supply_monitoring_test_data.sql

@@ -1,240 +0,0 @@
--- ============================================================
--- 供水管网 T4 运行监测 测试数据脚本(KingbaseES)
--- 说明:
---   1. 测试主键均使用 WS-TEST- 前缀,可重复执行;设备编码遵循新命名规范。
---   2. 设备编码遵循“区域-类型-YYYYMMDD+4位流水号”规范。
---   3. 本脚本只初始化测试行,不创建监测业务表;执行前请确认以下表已存在:
---      app_user.equipment_type、app_user.equipment_base、app_user.radar_data、
---      app_user.telemetry_data、app_user.firefighting_pressure、app_user.noise_info
---      如测量表 device_code 仍为 varchar(10),请先执行 migration_monitoring_device_code_length.sql。
---   4. 覆盖场景:雷达流量、遥测流量、压力、漏失、无数据设备、
---      非供水设备排除、数值范围过滤、时间范围过滤与近24小时之外的旧趋势点。
--- ============================================================
-
--- ------------------------------------------------------------
--- 0. 清理历史测试数据(先清测量值,再清设备;不删除生产设备类型)
--- ------------------------------------------------------------
-DELETE FROM app_user.radar_data WHERE id LIKE 'WS-TEST-%';
-DELETE FROM app_user.telemetry_data WHERE id LIKE 'WS-TEST-%';
-DELETE FROM app_user.firefighting_pressure WHERE id LIKE 'WS-TEST-%';
-DELETE FROM app_user.noise_info WHERE encode LIKE 'WS-TEST-%' OR encode LIKE 'CB-GS-20260902000%' OR encode LIKE 'TC-GS-20260902000%';
-DELETE FROM app_user.equipment_base WHERE equipment_id LIKE 'WS-TEST-EQ-%';
-
--- ------------------------------------------------------------
--- 1. 复用既有设备类型:id=1/type_id=water_supply,监测子类型严格挂在 parent_type_id=1
--- ------------------------------------------------------------
-DO $$
-DECLARE
-    v_type_count integer;
-BEGIN
-    SELECT count(*) INTO v_type_count
-      FROM app_user.equipment_type
-     WHERE id = '1' AND type_id = 'water_supply' AND parent_type_id = '0';
-    IF v_type_count <> 1 THEN
-        RAISE EXCEPTION '缺少规范供水顶级设备类型:id=1,type_id=water_supply,parent_type_id=0';
-    END IF;
-    SELECT count(*) INTO v_type_count
-      FROM app_user.equipment_type
-     WHERE type_id IN ('ws_flow', 'ws_pressure', 'ws_leak')
-       AND parent_type_id = '1';
-    IF v_type_count <> 3 THEN
-        RAISE EXCEPTION '缺少规范供水监测子类型:ws_flow/ws_pressure/ws_leak 必须 parent_type_id=1';
-    END IF;
-    SELECT count(*) INTO v_type_count
-      FROM app_user.equipment_type
-     WHERE id <> '1' AND type_id NOT IN ('water_supply', 'ws_flow', 'ws_pressure', 'ws_leak');
-    IF v_type_count = 0 THEN
-        RAISE EXCEPTION '缺少非供水设备类型,无法构造边界排除样本';
-    END IF;
-END $$;
-
-INSERT INTO app_user.equipment_base
-    (equipment_id, equipment_code, equipment_name, equipment_model, equipment_type_id,
-     longitude, latitude, equipment_location, maintainer, maintainer_phone,
-     ownership_unit, remark, create_time, update_time, del_flag, district)
-VALUES
-    ('WS-TEST-EQ-FLOW-RADAR', 'CN-GS-202609020001', '测试雷达流量监测点', 'RADAR-FLOW-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.28000000, 23.12000000, '供水测试大道1号',
-     '供水测试维护员', '13800000001', '供水测试公司', '供水T4运行监测测试数据',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-TELEMETRY', 'CN-GS-202609020002', '测试遥测终端流量监测点', 'TELEMETRY-FLOW-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.29000000, 23.13000000, '供水测试大道2号',
-     '供水测试维护员', '13800000002', '供水测试公司', '供水T4运行监测测试数据',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-PRESSURE', 'CB-GS-202609020001', '测试压力监测点', 'PRESSURE-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1), 113.30000000, 23.14000000, '供水测试大道3号',
-     '供水测试维护员', '13800000003', '供水测试公司', '供水T4运行监测测试数据',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-LEAKAGE', 'TC-GS-202609020001', '测试漏失监测点', 'LEAKAGE-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_leak' AND parent_type_id = '1' LIMIT 1), 113.31000000, 23.15000000, '供水测试大道4号',
-     '供水测试维护员', '13800000004', '供水测试公司', '供水T4运行监测测试数据',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-EMPTY', 'CN-GS-202609020003', '测试无测量流量监测点', 'FLOW-EMPTY-TEST',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.32000000, 23.16000000, '供水测试大道5号',
-     '供水测试维护员', '13800000005', '供水测试公司', '供水T4运行监测无数据测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-003', 'CN-GS-202609020004', '测试流量监测点03', 'FLOW-TEST-003',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.34000000, 23.18000000, '供水测试大道7号',
-     '供水测试维护员', '13800000007', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-004', 'CN-GS-202609020005', '测试流量监测点04', 'FLOW-TEST-004',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.35000000, 23.19000000, '供水测试大道8号',
-     '供水测试维护员', '13800000008', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-005', 'CN-GS-202609020006', '测试流量监测点05', 'FLOW-TEST-005',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.36000000, 23.20000000, '供水测试大道9号',
-     '供水测试维护员', '13800000009', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-006', 'CN-GS-202609020007', '测试流量监测点06', 'FLOW-TEST-006',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.37000000, 23.21000000, '供水测试大道10号',
-     '供水测试维护员', '13800000010', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-007', 'CN-GS-202609020008', '测试流量监测点07', 'FLOW-TEST-007',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.38000000, 23.22000000, '供水测试大道11号',
-     '供水测试维护员', '13800000011', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-008', 'CN-GS-202609020009', '测试流量监测点08', 'FLOW-TEST-008',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.39000000, 23.23000000, '供水测试大道12号',
-     '供水测试维护员', '13800000012', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-009', 'CN-GS-202609020010', '测试流量监测点09', 'FLOW-TEST-009',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.40000000, 23.24000000, '供水测试大道13号',
-     '供水测试维护员', '13800000013', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-010', 'CN-GS-202609020011', '测试流量监测点10', 'FLOW-TEST-010',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.41000000, 23.25000000, '供水测试大道14号',
-     '供水测试维护员', '13800000014', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-011', 'CN-GS-202609020012', '测试流量监测点11', 'FLOW-TEST-011',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.42000000, 23.26000000, '供水测试大道15号',
-     '供水测试维护员', '13800000015', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-FLOW-012', 'CN-GS-202609020013', '测试流量监测点12', 'FLOW-TEST-012',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_flow' AND parent_type_id = '1' LIMIT 1), 113.43000000, 23.27000000, '供水测试大道16号',
-     '供水测试维护员', '13800000016', '供水测试公司', '供水T4流量分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-PRESSURE-002', 'CB-GS-202609020002', '测试压力监测点02', 'PRESSURE-TEST-002',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1), 113.44000000, 23.28000000, '供水测试大道17号',
-     '供水测试维护员', '13800000017', '供水测试公司', '供水T4压力分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-PRESSURE-003', 'CB-GS-202609020003', '测试压力监测点03', 'PRESSURE-TEST-003',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_pressure' AND parent_type_id = '1' LIMIT 1), 113.45000000, 23.29000000, '供水测试大道18号',
-     '供水测试维护员', '13800000018', '供水测试公司', '供水T4压力分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-LEAKAGE-002', 'TC-GS-202609020002', '测试漏失监测点02', 'LEAKAGE-TEST-002',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_leak' AND parent_type_id = '1' LIMIT 1), 113.46000000, 23.30000000, '供水测试大道19号',
-     '供水测试维护员', '13800000019', '供水测试公司', '供水T4漏失分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-LEAKAGE-003', 'TC-GS-202609020003', '测试漏失监测点03', 'LEAKAGE-TEST-003',
-     (SELECT id FROM app_user.equipment_type WHERE type_id = 'ws_leak' AND parent_type_id = '1' LIMIT 1), 113.47000000, 23.31000000, '供水测试大道20号',
-     '供水测试维护员', '13800000020', '供水测试公司', '供水T4漏失分页测试设备',
-     now() - interval '7 days', now(), '0', '供水测试区'),
-    ('WS-TEST-EQ-OTHER-FLOW', 'CN-RQ-202609020001', '测试非供水流量监测点', 'OTHER-FLOW-TEST',
-     (SELECT id FROM app_user.equipment_type
-       WHERE id <> '1' AND type_id NOT IN ('water_supply', 'ws_flow', 'ws_pressure', 'ws_leak')
-       LIMIT 1), 113.33000000, 23.17000000, '其他系统测试大道6号',
-     '供水测试维护员', '13800000006', '供水测试公司', '供水T4非供水设备边界测试数据',
-     now() - interval '7 days', now(), '0', '供水测试区');
-
--- ------------------------------------------------------------
--- 2. 雷达流量计数据
---    数值范围 20-40 时:最新 120 不符合,应回退到 30。
---    5 天前数据用于验证趋势时间范围过滤。
--- ------------------------------------------------------------
-INSERT INTO app_user.radar_data
-    (id, system_identifier, device_code, meter1_instant_flow, flow_speed, create_time)
-VALUES
-    ('WS-TEST-RADAR-FLOW-001', 'WS-TEST-SYSTEM', 'CN-GS-202609020001', '30', '1.20',
-     now() - interval '3 hours'),
-    ('WS-TEST-RADAR-FLOW-002', 'WS-TEST-SYSTEM', 'CN-GS-202609020001', '120', '3.50',
-     now() - interval '1 hour'),
-    ('WS-TEST-RADAR-FLOW-003', 'WS-TEST-SYSTEM', 'CN-GS-202609020001', '18', '0.80',
-     now() - interval '5 days'),
-    ('WS-TEST-RADAR-FLOW-004', 'WS-TEST-SYSTEM', 'CN-GS-202609020004', '25', '1.00', now() - interval '1 hour'),
-    ('WS-TEST-RADAR-FLOW-005', 'WS-TEST-SYSTEM', 'CN-GS-202609020005', '35', '1.10', now() - interval '2 hours'),
-    ('WS-TEST-RADAR-FLOW-006', 'WS-TEST-SYSTEM', 'CN-GS-202609020006', '45', '1.20', now() - interval '3 hours'),
-    ('WS-TEST-RADAR-FLOW-007', 'WS-TEST-SYSTEM', 'CN-GS-202609020007', '55', '1.30', now() - interval '4 hours'),
-    ('WS-TEST-RADAR-FLOW-008', 'WS-TEST-SYSTEM', 'CN-GS-202609020008', '65', '1.40', now() - interval '5 hours'),
-    ('WS-TEST-RADAR-OTHER-FLOW-001', 'WS-TEST-SYSTEM', 'CN-RQ-202609020001', '66', '2.00',
-     now() - interval '1 hour');
-
--- ------------------------------------------------------------
--- 3. 遥测终端流量数据(device_code 与 equipment_base.equipment_code 关联)
--- ------------------------------------------------------------
-INSERT INTO app_user.telemetry_data
-    (id, system_identifier, device_code, meter1_instant_flow, meter1_positive_total,
-     flow_speed, temperature, create_time)
-VALUES
-    ('WS-TEST-TELEMETRY-001', 'WS-TEST-SYSTEM', 'CN-GS-202609020002', '42', '12345',
-     '1.80', '24.50', now() - interval '2 hours'),
-    ('WS-TEST-TELEMETRY-002', 'WS-TEST-SYSTEM', 'CN-GS-202609020002', '36', '12300',
-     '1.50', '24.00', now() - interval '4 hours'),
-    ('WS-TEST-TELEMETRY-003', 'WS-TEST-SYSTEM', 'CN-GS-202609020002', '20', '12200',
-     '0.90', '23.50', now() - interval '5 days');
-INSERT INTO app_user.telemetry_data
-    (id, system_identifier, device_code, meter1_instant_flow, meter1_positive_total,
-     flow_speed, temperature, create_time)
-VALUES
-    ('WS-TEST-TELEMETRY-004', 'WS-TEST-SYSTEM', 'CN-GS-202609020009', '18', '10008', '0.80', '23.80', now() - interval '1 hour'),
-    ('WS-TEST-TELEMETRY-005', 'WS-TEST-SYSTEM', 'CN-GS-202609020010', '28', '10009', '0.90', '23.90', now() - interval '2 hours'),
-    ('WS-TEST-TELEMETRY-006', 'WS-TEST-SYSTEM', 'CN-GS-202609020011', '38', '10010', '1.00', '24.10', now() - interval '3 hours'),
-    ('WS-TEST-TELEMETRY-007', 'WS-TEST-SYSTEM', 'CN-GS-202609020012', '48', '10011', '1.10', '24.20', now() - interval '4 hours'),
-    ('WS-TEST-TELEMETRY-008', 'WS-TEST-SYSTEM', 'CN-GS-202609020013', '58', '10012', '1.20', '24.30', now() - interval '5 hours');
-
--- ------------------------------------------------------------
--- 4. 消防压力数据(telemetering_station 与 equipment_base.equipment_code 关联)
--- ------------------------------------------------------------
-INSERT INTO app_user.firefighting_pressure
-    (id, central_station, telemetering_station, sending_time, observed_time,
-     pressure_value, create_time)
-VALUES
-    ('WS-TEST-PRESSURE-001', 'WS-TEST-CENTER', 'CB-GS-202609020001',
-     now() - interval '3 hours', now() - interval '3 hours', 0.42, now() - interval '3 hours'),
-    ('WS-TEST-PRESSURE-002', 'WS-TEST-CENTER', 'CB-GS-202609020001',
-     now() - interval '1 hour', now() - interval '1 hour', 0.95, now() - interval '1 hour'),
-    ('WS-TEST-PRESSURE-003', 'WS-TEST-CENTER', 'CB-GS-202609020001',
-     now() - interval '5 days', now() - interval '5 days', 0.20, now() - interval '5 days');
-INSERT INTO app_user.firefighting_pressure
-    (id, central_station, telemetering_station, sending_time, observed_time,
-     pressure_value, create_time)
-VALUES
-    ('WS-TEST-PRESSURE-004', 'WS-TEST-CENTER', 'CB-GS-202609020002',
-     now() - interval '2 hours', now() - interval '2 hours', 0.55, now() - interval '2 hours'),
-    ('WS-TEST-PRESSURE-005', 'WS-TEST-CENTER', 'CB-GS-202609020003',
-     now() - interval '1 hour', now() - interval '1 hour', 0.75, now() - interval '1 hour');
-
--- ------------------------------------------------------------
--- 5. 漏失噪声数据(encode 与 equipment_base.equipment_code 关联)
--- ------------------------------------------------------------
-INSERT INTO app_user.noise_info
-    (encode, power, gain, rms, center_frequency, ts, create_time, update_time)
-VALUES
-    ('TC-GS-202609020001', 12.00, 2.00, 120, 800.00,
-     to_char(now() - interval '2 hours', 'YYYY-MM-DD HH24:MI:SS'),
-     now() - interval '2 hours', now() - interval '2 hours'),
-    ('TC-GS-202609020001', 9.00, 2.00, 100, 780.00,
-     to_char(now() - interval '4 hours', 'YYYY-MM-DD HH24:MI:SS'),
-     now() - interval '4 hours', now() - interval '4 hours'),
-    ('TC-GS-202609020001', 5.00, 1.00, 80, 700.00,
-     to_char(now() - interval '5 days', 'YYYY-MM-DD HH24:MI:SS'),
-     now() - interval '5 days', now() - interval '5 days');
-INSERT INTO app_user.noise_info
-    (encode, power, gain, rms, center_frequency, ts, create_time, update_time)
-VALUES
-    ('TC-GS-202609020002', 15.00, 2.50, 125, 820.00,
-     to_char(now() - interval '1 hour', 'YYYY-MM-DD HH24:MI:SS'),
-     now() - interval '1 hour', now() - interval '1 hour'),
-    ('TC-GS-202609020003', 18.00, 3.00, 130, 840.00,
-     to_char(now() - interval '2 hours', 'YYYY-MM-DD HH24:MI:SS'),
-     now() - interval '2 hours', now() - interval '2 hours');
-
--- ------------------------------------------------------------
--- 快速核验:
---   规范 ws_flow 流量设备共13台(其中12台有 radar/telemetry 测量记录,1台无数据);
---   流量分页(默认最新值):12台有测量设备各返回1条;雷达流量点最新值120,遥测流量点最新值42;
---   流量分页 flowMin=20&flowMax=40:符合范围的雷达/遥测点共7条(含回退到雷达30、遥测36);
---   压力分页 pressureMin=0.30&pressureMax=0.60:0.42、0.55,共2条;
---   漏失分页 powerMin=8&powerMax=15:12、15,共2条;
---   CN-GS-202609020003 无测量数据,不应出现在任何监测页。
---   CN-RQ-202609020001 如数据库存在其他系统类型则带入该类型;不在供水规范子类型内,不应出现在监测页。
--- ============================================================

+ 11 - 10
pipe-network-service/sql/water_supply_threshold_test_data.sql

@@ -1,8 +1,9 @@
 -- ============================================================
 -- 供水管网 T5 阈值管理 测试数据脚本(KingbaseES)
 -- 说明:
---   1. 依赖 T4 已初始化的规范设备类型和供水监测设备:
---      ws_flow / ws_pressure / ws_leak,父类型 parent_type_id=1。
+--   1. 依赖 water_supply_monitoring_alarm_rebuild_test_data.sql 初始化后的供水监测设备;
+--      设备类型一律以库中现值为权威:ultrasonic_flowmeter / pressure_gauge / leak_monitor,
+--      父类型 parent_type_id=1(不再引用已不存在的旧监测类型标识)。
 --   2. 阈值测试主键使用 WS-TEST-THR- 前缀,可重复执行。
 --   3. 覆盖全天生效、分时生效、流量/压力/漏失三类传感器和筛选场景。
 -- ============================================================
@@ -19,10 +20,10 @@ DECLARE
 BEGIN
     SELECT count(*) INTO v_type_count
       FROM app_user.equipment_type
-     WHERE type_id IN ('ws_flow', 'ws_pressure', 'ws_leak')
+     WHERE type_id IN ('ultrasonic_flowmeter', 'pressure_gauge', 'leak_monitor')
        AND parent_type_id = '1';
     IF v_type_count <> 3 THEN
-        RAISE EXCEPTION '缺少规范供水监测子类型:ws_flow/ws_pressure/ws_leak 必须 parent_type_id=1';
+        RAISE EXCEPTION '缺少规范供水监测子类型:ultrasonic_flowmeter/pressure_gauge/leak_monitor 必须 parent_type_id=1';
     END IF;
 END $$;
 
@@ -30,22 +31,22 @@ INSERT INTO app_user.warning_threshold
     (id, device_code, warning_type, warning_code, min_value, max_value,
      period_start, period_end, remark, create_time, update_time)
 VALUES
-    ('WS-TEST-THR-FLOW-ALL', 'CN-GS-202609020001', '流量预警', 'WARN-T5-FLOW',
+    ('WS-TEST-THR-FLOW-ALL', 'CN-GS-202609160201', '流量预警', 'WARN-T5-FLOW',
      20.00, 40.00, NULL, NULL, '供水T5阈值测试-流量全天生效',
      now(), now()),
-    ('WS-TEST-THR-FLOW-PERIOD', 'CN-GS-202609020002', '流量预警', 'WARN-T5-FLOW',
+    ('WS-TEST-THR-FLOW-PERIOD', 'CB-GS-202609160202', '流量预警', 'WARN-T5-FLOW',
      25.00, 45.00, '08:00', '20:00', '供水T5阈值测试-流量分时生效',
      now(), now()),
-    ('WS-TEST-THR-PRESSURE-ALL', 'CB-GS-202609020001', '压力预警', 'WARN-T5-PRESSURE',
+    ('WS-TEST-THR-PRESSURE-ALL', 'CN-GS-202609160211', '压力预警', 'WARN-T5-PRESSURE',
      0.30, 0.60, NULL, NULL, '供水T5阈值测试-压力全天生效',
      now(), now()),
-    ('WS-TEST-THR-LEAK-PERIOD', 'TC-GS-202609020001', '漏失预警', 'WARN-T5-LEAK',
+    ('WS-TEST-THR-LEAK-PERIOD', 'CN-GS-202609160221', '漏失预警', 'WARN-T5-LEAK',
      8.00, 15.00, '08:00', '20:00', '供水T5阈值测试-漏失分时生效',
      now(), now());
 
 -- 快速核验:
 --   阈值分页 total=4;
---   设备编码筛选 CN-GS-202609020001 返回 1 条;
+--   设备编码筛选 CN-GS-202609160201 返回 1 条;
 --   预警分类筛选 流量预警 返回 2 条;
---   WARN-T5-FLOW 在 CN-GS-202609020002 上已存在 08:00-20:00,
+--   WARN-T5-FLOW 在 CB-GS-202609160202 上已存在 08:00-20:00,
 --   再次保存 19:00-21:00 应返回重叠时段错误。

+ 121 - 0
pipe-network-service/zksy-system/src/test/java/com/zksy/WaterSupply/Monitoring/MonitoringFixtureTypeContractTest.java

@@ -0,0 +1,121 @@
+package com.zksy.WaterSupply.Monitoring;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Gogs #56 / T05:供水监测与报警测试数据必须以库中真实的 equipment_type 为权威。
+ *
+ * <p>本轮迁移后供水子类型是 {@code ultrasonic_flowmeter} / {@code pressure_gauge} /
+ * {@code leak_monitor}({@code parent_type_id = '1'})。旧种子脚本按已不存在的
+ * {@code ws_flow} / {@code ws_pressure} / {@code ws_leak} 取类型,执行到一半即中断,
+ * 造成运行监测三页空列表、设备台账类型错位、报警台账只剩少量能对上设备的记录。
+ * 本测试把「不再引用旧类型标识、旧种子已退役、统一脚本存在且不新增设备类型」钉死。</p>
+ */
+class MonitoringFixtureTypeContractTest {
+
+    private static final String UNIFIED_SEED = "sql/water_supply_monitoring_alarm_rebuild_test_data.sql";
+
+    /** 已退役的旧种子脚本:统一脚本已完整取代它们。 */
+    private static final Set<String> RETIRED_SEEDS = Set.of(
+            "sql/water_supply_monitoring_test_data.sql",
+            "sql/water_supply_device_test_data.sql",
+            "sql/water_supply_abnormal_test_data.sql",
+            "sql/water_supply_alarm_ledger_test_data.sql",
+            "sql/water_supply_alarm_audit_test_data.sql");
+
+    private static final List<String> LEGACY_TYPE_TOKENS = List.of("ws_flow", "ws_pressure", "ws_leak");
+
+    private static final List<String> REAL_MONITORING_TYPE_IDS = List.of(
+            "ultrasonic_flowmeter", "pressure_gauge", "leak_monitor");
+
+    private static final String MONITORING_SERVICE =
+            "zksy-system/src/main/java/com/zksy/base/service/impl/MonitoringServiceImpl.java";
+
+    @Test
+    void sqlSeedsNoLongerReferenceRetiredWaterMonitoringTypeIds() throws IOException {
+        Path repoRoot = repoRoot();
+        List<String> offenders = new ArrayList<>();
+        try (Stream<Path> walk = Files.walk(repoRoot.resolve("sql"))) {
+            for (Path file : walk.filter(Files::isRegularFile)
+                    .filter(path -> path.toString().endsWith(".sql"))
+                    .toList()) {
+                String relative = repoRoot.relativize(file).toString().replace('\\', '/');
+                if (UNIFIED_SEED.equals(relative)) {
+                    // 统一脚本在文件头说明历史原因时会提到旧标识,只允许它自己引用。
+                    continue;
+                }
+                String content = Files.readString(file, StandardCharsets.UTF_8);
+                for (String token : LEGACY_TYPE_TOKENS) {
+                    if (content.contains(token)) {
+                        offenders.add(relative + " -> " + token);
+                    }
+                }
+            }
+        }
+        assertTrue(offenders.isEmpty(),
+                "供水监测类型以库中 equipment_type 为权威,以下脚本仍引用已不存在的旧类型标识:\n"
+                        + String.join("\n", offenders));
+    }
+
+    @Test
+    void retiredWaterMonitoringSeedsAreGone() {
+        Path repoRoot = repoRoot();
+        List<String> stillPresent = new ArrayList<>();
+        for (String retired : RETIRED_SEEDS) {
+            if (Files.exists(repoRoot.resolve(retired))) {
+                stillPresent.add(retired);
+            }
+        }
+        assertTrue(stillPresent.isEmpty(), "以下种子脚本已被统一脚本取代,不应继续留在仓库:" + stillPresent);
+        assertTrue(Files.exists(repoRoot.resolve(UNIFIED_SEED)),
+                "统一重建脚本必须存在:" + UNIFIED_SEED);
+    }
+
+    @Test
+    void unifiedSeedUsesOnlyExistingMonitoringTypesAndAddsNoNewType() throws IOException {
+        String sql = Files.readString(repoRoot().resolve(UNIFIED_SEED), StandardCharsets.UTF_8);
+        for (String typeId : REAL_MONITORING_TYPE_IDS) {
+            assertTrue(sql.contains("type_id = '" + typeId + "'"),
+                    "统一脚本必须按库中真实 type_id 定位监测类型:" + typeId);
+        }
+        assertFalse(sql.contains("INSERT INTO app_user.equipment_type"),
+                "统一脚本不得新增设备类型,只能引用 equipment_type 现有记录");
+        assertTrue(sql.contains("parent_type_id = '1'"),
+                "供水监测类型必须限定在供水顶级类型(parent_type_id = '1')之下");
+    }
+
+    @Test
+    void monitoringServiceConstantsMatchTheAuthoritativeDatabaseTypeIds() throws IOException {
+        String source = Files.readString(repoRoot().resolve(MONITORING_SERVICE), StandardCharsets.UTF_8);
+        assertTrue(source.contains("FLOW_TYPE_ID = \"ultrasonic_flowmeter\""),
+                "运行监测流量类型常量必须与库中 type_id 对齐");
+        assertTrue(source.contains("PRESSURE_TYPE_ID = \"pressure_gauge\""),
+                "运行监测压力类型常量必须与库中 type_id 对齐");
+        assertTrue(source.contains("LEAKAGE_TYPE_ID = \"leak_monitor\""),
+                "运行监测漏失类型常量必须与库中 type_id 对齐");
+    }
+
+    private static Path repoRoot() {
+        Path current = Paths.get(System.getProperty("user.dir")).toAbsolutePath();
+        while (current != null) {
+            if (Files.exists(current.resolve("zksy-system")) && Files.exists(current.resolve("sql"))) {
+                return current;
+            }
+            current = current.getParent();
+        }
+        throw new IllegalStateException("无法定位 pipe-network-service 仓库根目录");
+    }
+}