Pārlūkot izejas kodu

fix(water): use canonical monitoring type ids

Kazerin 2 dienas atpakaļ
vecāks
revīzija
acbb7c4e7a

+ 24 - 31
pipe-network-service/sql/water_supply_monitoring_test_data.sql

@@ -6,47 +6,38 @@
 --      app_user.equipment_type、app_user.equipment_base、app_user.radar_data、
 --      app_user.telemetry_data、app_user.firefighting_pressure、app_user.noise_info
 --   3. 覆盖场景:雷达流量、遥测流量、压力、漏失、无数据设备、
---      非供水同名设备排除、数值范围过滤、时间范围过滤与近24小时之外的旧趋势点。
+--      非供水设备排除、数值范围过滤、时间范围过滤与近24小时之外的旧趋势点。
 -- ============================================================
 
 -- ------------------------------------------------------------
--- 0. 清理历史测试数据(先清测量值,再清设备类型)
+-- 0. 清理历史测试数据(先清测量值,再清设备;不删除生产设备类型)
 -- ------------------------------------------------------------
 DELETE FROM app_user.radar_data WHERE device_code LIKE 'WS-TEST-%';
 DELETE FROM app_user.telemetry_data WHERE device_code LIKE 'WS-TEST-%';
 DELETE FROM app_user.firefighting_pressure WHERE telemetering_station LIKE 'WS-TEST-%';
 DELETE FROM app_user.noise_info WHERE encode LIKE 'WS-TEST-%';
 DELETE FROM app_user.equipment_base WHERE equipment_id LIKE 'WS-TEST-EQ-%';
-DELETE FROM app_user.equipment_type WHERE id LIKE 'WS-TEST-TYPE-%';
 
 -- ------------------------------------------------------------
--- 1. 设备类型与监测设备(供水测试类型挂在顶级类型“供水”之下)
+-- 1. 复用既有设备类型:id=1/type_id=water_supply,监测子类型严格挂在 parent_type_id=1
 -- ------------------------------------------------------------
 DO $$
 DECLARE
-    v_water_top_id varchar(64);
+    v_type_count integer;
 BEGIN
-    SELECT id INTO v_water_top_id
+    SELECT count(*) INTO v_type_count
       FROM app_user.equipment_type
-     WHERE type_name = '供水' AND parent_type_id = '0'
-     LIMIT 1;
-
-    IF v_water_top_id IS NULL THEN
-        INSERT INTO app_user.equipment_type
-            (id, type_id, type_name, parent_type_id, type_remark)
-        VALUES
-            ('WS-TEST-TYPE-WATER', 'ws_test_water_top', '供水', '0', '供水T4运行监测测试顶级类型');
-        v_water_top_id := 'WS-TEST-TYPE-WATER';
+     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;
-
-    INSERT INTO app_user.equipment_type
-        (id, type_id, type_name, parent_type_id, type_remark)
-    VALUES
-        ('WS-TEST-TYPE-FLOW', 'ws_test_flow_monitoring', '流量监测(测试)', v_water_top_id, '供水T4流量监测测试类型'),
-        ('WS-TEST-TYPE-PRESSURE', 'ws_test_pressure_monitoring', '压力监测(测试)', v_water_top_id, '供水T4压力监测测试类型'),
-        ('WS-TEST-TYPE-LEAKAGE', 'ws_test_leakage_monitoring', '漏失监测(测试)', v_water_top_id, '供水T4漏失监测测试类型'),
-        ('WS-TEST-TYPE-OTHER', 'ws_test_other_top', '其他系统(测试)', '0', '供水T4边界测试顶级类型'),
-        ('WS-TEST-TYPE-OTHER-FLOW', 'ws_test_other_flow', '流量监测(测试)', 'WS-TEST-TYPE-OTHER', '供水T4非供水边界测试类型');
 END $$;
 
 INSERT INTO app_user.equipment_base
@@ -55,27 +46,29 @@ INSERT INTO app_user.equipment_base
      ownership_unit, remark, create_time, update_time, del_flag, district)
 VALUES
     ('WS-TEST-EQ-FLOW-RADAR', 'WS-TEST-FLOW-RADAR', '测试雷达流量监测点', 'RADAR-FLOW-TEST',
-     'WS-TEST-TYPE-FLOW', 113.28000000, 23.12000000, '供水测试大道1号',
+     (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', 'WS-TEST-FLOW-TELEMETRY', '测试遥测终端流量监测点', 'TELEMETRY-FLOW-TEST',
-     'WS-TEST-TYPE-FLOW', 113.29000000, 23.13000000, '供水测试大道2号',
+     (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', 'WS-TEST-PRESSURE', '测试压力监测点', 'PRESSURE-TEST',
-     'WS-TEST-TYPE-PRESSURE', 113.30000000, 23.14000000, '供水测试大道3号',
+     (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', 'WS-TEST-LEAKAGE', '测试漏失监测点', 'LEAKAGE-TEST',
-     'WS-TEST-TYPE-LEAKAGE', 113.31000000, 23.15000000, '供水测试大道4号',
+     (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', 'WS-TEST-FLOW-EMPTY', '测试无测量流量监测点', 'FLOW-EMPTY-TEST',
-     'WS-TEST-TYPE-FLOW', 113.32000000, 23.16000000, '供水测试大道5号',
+     (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-OTHER-FLOW', 'WS-TEST-OTHER-FLOW', '测试非供水流量监测点', 'OTHER-FLOW-TEST',
-     'WS-TEST-TYPE-OTHER-FLOW', 113.33000000, 23.17000000, '其他系统测试大道6号',
+     (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', '供水测试区');
 
@@ -147,5 +140,5 @@ VALUES
 --   压力分页 pressureMin=0.30&pressureMax=0.60:0.42,共1条;
 --   漏失分页 powerMin=8&powerMax=15:12,共1条;
 --   WS-TEST-FLOW-EMPTY 无测量数据,不应出现在任何监测页。
---   WS-TEST-OTHER-FLOW 有同名流量类型和测量数据,但不在供水类型树内,不应出现在任何监测页。
+--   WS-TEST-OTHER-FLOW 如数据库存在其他系统类型则带入该类型;不在供水规范子类型内,不应出现在监测页。
 -- ============================================================

+ 21 - 43
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/impl/MonitoringServiceImpl.java

@@ -20,7 +20,6 @@ import com.zksy.base.radar.mapper.RadarDataMapper;
 import com.zksy.base.service.MonitoringService;
 import com.zksy.base.telemetry.domain.TelemetryData;
 import com.zksy.base.telemetry.mapper.TelemetryDataMapper;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -35,8 +34,12 @@ public class MonitoringServiceImpl implements MonitoringService {
     private static final String RADAR_SOURCE = "雷达流量计";
     private static final String TELEMETRY_SOURCE = "遥测终端";
 
-    @Value("${waterSupply.monitoring.top-level-type:供水}")
-    private String waterSupplyTopLevelType = "供水";
+    private static final String WATER_SUPPLY_ROOT_ID = "1";
+    private static final String WATER_SUPPLY_ROOT_TYPE_ID = "water_supply";
+    private static final String WATER_SUPPLY_ROOT_PARENT_ID = "0";
+    private static final String FLOW_TYPE_ID = "ws_flow";
+    private static final String PRESSURE_TYPE_ID = "ws_pressure";
+    private static final String LEAKAGE_TYPE_ID = "ws_leak";
 
     @Autowired
     private EquipmentBaseMapper equipmentBaseMapper;
@@ -514,60 +517,35 @@ public class MonitoringServiceImpl implements MonitoringService {
         return endTime != null ? null : LocalDateTime.now().minusHours(24);
     }
 
-    /** Restrict monitoring pages to sub-devices inside the configured water-supply type tree. */
+    /** Restrict monitoring pages and trends to the canonical water-supply monitoring types. */
     private Set<String> selectMonitoringTypeIds(String monitorKind) {
-        String[] keywords;
+        String typeId;
         switch (monitorKind) {
             case "pressure":
-                keywords = new String[]{"压力", "pressure", "消防"};
+                typeId = PRESSURE_TYPE_ID;
                 break;
             case "leakage":
-                keywords = new String[]{"漏失", "漏损", "泄漏", "噪声", "音频", "noise"};
+                typeId = LEAKAGE_TYPE_ID;
                 break;
-            default:
-                keywords = new String[]{"流量", "flow", "雷达", "遥测", "telemetry"};
+            case "flow":
+                typeId = FLOW_TYPE_ID;
                 break;
+            default:
+                return Collections.emptySet();
         }
         List<EquipmentType> types = equipmentTypeMapper.selectList(new LambdaQueryWrapper<>());
-        Set<String> waterTypeIds = waterSupplyTypeTreeIds(types);
-        if (waterTypeIds.isEmpty()) {
+        boolean hasCanonicalWaterSupplyRoot = types.stream()
+                .anyMatch(type -> WATER_SUPPLY_ROOT_ID.equals(type.getId())
+                        && WATER_SUPPLY_ROOT_TYPE_ID.equals(type.getTypeId())
+                        && WATER_SUPPLY_ROOT_PARENT_ID.equals(type.getParentTypeId()));
+        if (!hasCanonicalWaterSupplyRoot) {
             return Collections.emptySet();
         }
         return types.stream()
-                .filter(type -> waterTypeIds.contains(type.getId()))
-                .filter(type -> {
-                    String value = ((type.getTypeId() == null ? "" : type.getTypeId()) + " "
-                            + (type.getTypeName() == null ? "" : type.getTypeName())).toLowerCase(Locale.ROOT);
-                    return Arrays.stream(keywords).anyMatch(keyword -> value.contains(keyword.toLowerCase(Locale.ROOT)));
-                })
+                .filter(type -> typeId.equals(type.getTypeId()))
+                .filter(type -> WATER_SUPPLY_ROOT_ID.equals(type.getParentTypeId()))
                 .map(EquipmentType::getId)
                 .filter(StrUtil::isNotBlank)
                 .collect(Collectors.toSet());
     }
-
-    private Set<String> waterSupplyTypeTreeIds(List<EquipmentType> types) {
-        Map<String, List<EquipmentType>> childrenByParent = types.stream()
-                .filter(type -> StrUtil.isNotBlank(type.getParentTypeId()) && StrUtil.isNotBlank(type.getId()))
-                .collect(Collectors.groupingBy(EquipmentType::getParentTypeId));
-
-        Set<String> typeIds = new LinkedHashSet<>();
-        Deque<String> pending = types.stream()
-                .filter(type -> "0".equals(type.getParentTypeId())
-                        && waterSupplyTopLevelType.equals(type.getTypeName())
-                        && StrUtil.isNotBlank(type.getId()))
-                .map(EquipmentType::getId)
-                .collect(Collectors.toCollection(ArrayDeque::new));
-        while (!pending.isEmpty()) {
-            String typeId = pending.poll();
-            if (!typeIds.add(typeId)) {
-                continue;
-            }
-            childrenByParent.getOrDefault(typeId, Collections.emptyList())
-                    .stream()
-                    .map(EquipmentType::getId)
-                    .filter(StrUtil::isNotBlank)
-                    .forEach(pending::offer);
-        }
-        return typeIds;
-    }
 }

+ 43 - 32
pipe-network-service/zksy-system/src/test/java/com/zksy/base/service/impl/MonitoringServiceImplTest.java

@@ -79,10 +79,10 @@ class MonitoringServiceImplTest {
         ReflectionTestUtils.setField(service, "noiseInfoMapper", noiseMapper);
 
         when(equipmentTypeMapper.selectList(any())).thenReturn(Arrays.asList(
-                type("water-root", "water_root", "供水", "0"),
-                type("flow-type", "flow-type", "流量监测", "water-root"),
-                type("pressure-type", "pressure-type", "压力监测", "water-root"),
-                type("leakage-type", "leakage-type", "漏失监测", "water-root")
+                type("1", "water_supply", "供水", "0"),
+                type("11", "ws_flow", "供水流量计", "1"),
+                type("12", "ws_pressure", "供水压力计", "1"),
+                type("13", "ws_leak", "供水漏失监测器", "1")
         ));
         when(radarDataMapper.selectList(any())).thenReturn(Collections.emptyList());
         when(telemetryDataMapper.selectList(any())).thenReturn(Collections.emptyList());
@@ -93,8 +93,8 @@ class MonitoringServiceImplTest {
     @Test
     void flowPaginationTotalsFollowMeasurementFilteringAndKeepDeviceFields() {
         when(equipmentBaseMapper.selectList(any())).thenReturn(Arrays.asList(
-                device("flow-1", "WS-FLOW-1", "流量监测点1", "flow-type", BASE_TIME),
-                device("flow-2", "WS-FLOW-2", "流量监测点2", "flow-type", BASE_TIME.minusMinutes(1))
+                device("flow-1", "WS-FLOW-1", "流量监测点1", "11", BASE_TIME),
+                device("flow-2", "WS-FLOW-2", "流量监测点2", "11", BASE_TIME.minusMinutes(1))
         ));
         when(radarDataMapper.selectList(any())).thenReturn(Arrays.asList(
                 radar("WS-FLOW-1", "100", BASE_TIME),
@@ -111,7 +111,7 @@ class MonitoringServiceImplTest {
         assertEquals("flow-1", row.getEquipmentId());
         assertEquals("WS-FLOW-1", row.getEquipmentCode());
         assertEquals("流量监测点1", row.getEquipmentName());
-        assertEquals("流量监测", row.getEquipmentTypeName());
+        assertEquals("供水流量计", row.getEquipmentTypeName());
         assertEquals("30", row.getInstantFlow());
         assertEquals(BASE_TIME.minusHours(1), row.getMonitorTime());
     }
@@ -119,7 +119,7 @@ class MonitoringServiceImplTest {
     @Test
     void flowPaginationUsesTheNewestQualifyingMeasurementAcrossDataSources() {
         when(equipmentBaseMapper.selectList(any())).thenReturn(Collections.singletonList(
-                device("flow-1", "WS-FLOW-1", "流量监测点1", "flow-type", BASE_TIME)
+                device("flow-1", "WS-FLOW-1", "流量监测点1", "11", BASE_TIME)
         ));
         when(radarDataMapper.selectList(any())).thenReturn(Collections.singletonList(
                 radar("WS-FLOW-1", "30", BASE_TIME.minusHours(2))
@@ -141,9 +141,9 @@ class MonitoringServiceImplTest {
     @Test
     void pressurePaginationTotalsFollowMeasurementFiltering() {
         when(equipmentBaseMapper.selectList(any())).thenReturn(Arrays.asList(
-                device("pressure-1", "WS-PR-1", "压力监测点1", "pressure-type", BASE_TIME),
-                device("pressure-2", "WS-PR-2", "压力监测点2", "pressure-type", BASE_TIME.minusMinutes(1)),
-                device("pressure-3", "WS-PR-3", "压力监测点3", "pressure-type", BASE_TIME.minusMinutes(2))
+                device("pressure-1", "WS-PR-1", "压力监测点1", "12", BASE_TIME),
+                device("pressure-2", "WS-PR-2", "压力监测点2", "12", BASE_TIME.minusMinutes(1)),
+                device("pressure-3", "WS-PR-3", "压力监测点3", "12", BASE_TIME.minusMinutes(2))
         ));
         when(pressureMapper.selectList(any())).thenReturn(Arrays.asList(
                 pressure("WS-PR-1", 0.4D, BASE_TIME),
@@ -163,8 +163,8 @@ class MonitoringServiceImplTest {
     @Test
     void leakagePaginationExcludesDevicesWithoutQualifyingMeasurements() {
         when(equipmentBaseMapper.selectList(any())).thenReturn(Arrays.asList(
-                device("leakage-1", "WS-LK-1", "漏失监测点1", "leakage-type", BASE_TIME),
-                device("leakage-2", "WS-LK-2", "漏失监测点2", "leakage-type", BASE_TIME.minusMinutes(1))
+                device("leakage-1", "WS-LK-1", "漏失监测点1", "13", BASE_TIME),
+                device("leakage-2", "WS-LK-2", "漏失监测点2", "13", BASE_TIME.minusMinutes(1))
         ));
         when(noiseMapper.selectList(any())).thenReturn(Collections.singletonList(
                 noise("WS-LK-1", 12D, BASE_TIME)
@@ -183,7 +183,7 @@ class MonitoringServiceImplTest {
     @Test
     void monitoringPagesReturnAnEmptyPageWhenThereIsNoMeasurementData() {
         when(equipmentBaseMapper.selectList(any())).thenReturn(Collections.singletonList(
-                device("flow-empty", "WS-FLOW-EMPTY", "无数据监测点", "flow-type", BASE_TIME)
+                device("flow-empty", "WS-FLOW-EMPTY", "无数据监测点", "11", BASE_TIME)
         ));
 
         Page<FlowMonitoringVO> flow = service.getFlowMonitorPage(1, 10, null, null, null, null, null, null, null);
@@ -191,14 +191,14 @@ class MonitoringServiceImplTest {
         assertTrue(flow.getRecords().isEmpty());
 
         when(equipmentBaseMapper.selectList(any())).thenReturn(Collections.singletonList(
-                device("pressure-empty", "WS-PR-EMPTY", "无数据监测点", "pressure-type", BASE_TIME)
+                device("pressure-empty", "WS-PR-EMPTY", "无数据监测点", "12", BASE_TIME)
         ));
         Page<PressureMonitoringVO> pressure = service.getPressureMonitorPage(1, 10, null, null, null, null, null, null, null);
         assertEquals(0, pressure.getTotal());
         assertTrue(pressure.getRecords().isEmpty());
 
         when(equipmentBaseMapper.selectList(any())).thenReturn(Collections.singletonList(
-                device("leakage-empty", "WS-LK-EMPTY", "无数据监测点", "leakage-type", BASE_TIME)
+                device("leakage-empty", "WS-LK-EMPTY", "无数据监测点", "13", BASE_TIME)
         ));
         Page<LeakageMonitoringVO> leakage = service.getLeakageMonitorPage(1, 10, null, null, null, null, null, null, null);
         assertEquals(0, leakage.getTotal());
@@ -208,8 +208,11 @@ class MonitoringServiceImplTest {
     @Test
     void flowMonitoringOnlyIncludesDevicesInsideTheWaterTypeTree() {
         when(equipmentTypeMapper.selectList(any())).thenReturn(Arrays.asList(
-                type("water-root", "water_root", "供水", "0"),
-                type("water-flow", "water_flow", "流量监测", "water-root"),
+                type("1", "water_supply", "供水", "0"),
+                type("11", "ws_flow", "供水流量计", "1"),
+                type("99", "legacy_flow", "流量监测(旧编码)", "1"),
+                type("98", "ws_flow", "错误名称但真实流量编码", "1"),
+                type("97", "ws_flow", "供水流量计但父级错误", "other-root"),
                 type("other-root", "other_root", "其他系统", "0"),
                 type("other-flow", "other_flow", "流量监测", "other-root")
         ));
@@ -217,7 +220,10 @@ class MonitoringServiceImplTest {
             LambdaQueryWrapper<EquipmentBase> wrapper = invocation.getArgument(0);
             Set<Object> allowedTypeIds = flattenWrapperValues(wrapper);
             return Arrays.asList(
-                    device("water-flow-device", "WS-FLOW", "供水流量监测点", "water-flow", BASE_TIME),
+                    device("water-flow-device", "WS-FLOW", "供水流量监测点", "11", BASE_TIME),
+                    device("legacy-flow-device", "WS-LEGACY-FLOW", "旧编码流量监测点", "99", BASE_TIME),
+                    device("real-id-wrong-name-device", "WS-FLOW-WRONG-NAME", "真实编码流量监测点", "98", BASE_TIME),
+                    device("wrong-parent-flow-device", "WS-FLOW-WRONG-PARENT", "错误父级流量监测点", "97", BASE_TIME),
                     device("other-flow-device", "OTHER-FLOW", "其他系统流量监测点", "other-flow", BASE_TIME),
                     device("unknown-type-device", "UNKNOWN-FLOW", "未归属流量监测点", "unknown-type", BASE_TIME)
             ).stream()
@@ -226,6 +232,9 @@ class MonitoringServiceImplTest {
         });
         when(radarDataMapper.selectList(any())).thenReturn(Arrays.asList(
                 radar("WS-FLOW", "10", BASE_TIME),
+                radar("WS-LEGACY-FLOW", "20", BASE_TIME),
+                radar("WS-FLOW-WRONG-NAME", "30", BASE_TIME),
+                radar("WS-FLOW-WRONG-PARENT", "40", BASE_TIME),
                 radar("OTHER-FLOW", "20", BASE_TIME),
                 radar("UNKNOWN-FLOW", "30", BASE_TIME)
         ));
@@ -233,15 +242,17 @@ class MonitoringServiceImplTest {
         Page<FlowMonitoringVO> page = service.getFlowMonitorPage(
                 1, 10, null, null, null, null, null, null, null);
 
-        assertEquals(1, page.getTotal());
-        assertEquals("water-flow-device", page.getRecords().get(0).getEquipmentId());
+        assertEquals(2, page.getTotal());
+        assertEquals(
+                Set.of("water-flow-device", "real-id-wrong-name-device"),
+                page.getRecords().stream().map(FlowMonitoringVO::getEquipmentId).collect(Collectors.toSet()));
     }
 
     @Test
     void trendEndpointsRejectDevicesOutsideTheWaterTypeTree() {
         when(equipmentTypeMapper.selectList(any())).thenReturn(Arrays.asList(
-                type("water-root", "water_root", "供水", "0"),
-                type("water-flow", "water_flow", "流量监测", "water-root"),
+                type("1", "water_supply", "供水", "0"),
+                type("11", "ws_flow", "供水流量计", "1"),
                 type("other-root", "other_root", "其他系统", "0"),
                 type("other-flow", "other_flow", "流量监测", "other-root")
         ));
@@ -261,7 +272,7 @@ class MonitoringServiceImplTest {
         LocalDateTime start = BASE_TIME.minusHours(2);
         LocalDateTime end = BASE_TIME;
 
-        EquipmentBase flowDevice = device("flow-1", "WS-FLOW-1", "流量监测点1", "flow-type", BASE_TIME);
+        EquipmentBase flowDevice = device("flow-1", "WS-FLOW-1", "流量监测点1", "11", BASE_TIME);
         when(equipmentBaseMapper.selectById("flow-1")).thenReturn(flowDevice);
         when(radarDataMapper.selectList(any())).thenReturn(Arrays.asList(
                 radar("WS-FLOW-1", "10", BASE_TIME.minusHours(3)),
@@ -274,7 +285,7 @@ class MonitoringServiceImplTest {
         assertEquals(BASE_TIME.minusHours(1), flow.get(0).get("time"));
         assertEquals("WS-FLOW-1", flow.get(0).get("equipmentCode"));
 
-        EquipmentBase pressureDevice = device("pressure-1", "WS-PR-1", "压力监测点1", "pressure-type", BASE_TIME);
+        EquipmentBase pressureDevice = device("pressure-1", "WS-PR-1", "压力监测点1", "12", BASE_TIME);
         when(equipmentBaseMapper.selectById("pressure-1")).thenReturn(pressureDevice);
         when(pressureMapper.selectList(any())).thenReturn(Arrays.asList(
                 pressure("WS-PR-1", 0.1D, BASE_TIME.minusHours(3)),
@@ -286,7 +297,7 @@ class MonitoringServiceImplTest {
         assertEquals(0.2D, pressure.get(0).get("pressureValue"));
         assertEquals("WS-PR-1", pressure.get(0).get("equipmentCode"));
 
-        EquipmentBase leakageDevice = device("leakage-1", "WS-LK-1", "漏失监测点1", "leakage-type", BASE_TIME);
+        EquipmentBase leakageDevice = device("leakage-1", "WS-LK-1", "漏失监测点1", "13", BASE_TIME);
         when(equipmentBaseMapper.selectById("leakage-1")).thenReturn(leakageDevice);
         when(noiseMapper.selectList(any())).thenReturn(Arrays.asList(
                 noise("WS-LK-1", 1D, BASE_TIME.minusHours(3)),
@@ -301,7 +312,7 @@ class MonitoringServiceImplTest {
 
     @Test
     void trendEndpointWithOnlyAnEndTimeDoesNotApplyTheDefault24HourStart() {
-        EquipmentBase device = device("flow-1", "WS-FLOW-1", "流量监测点1", "flow-type", BASE_TIME);
+        EquipmentBase device = device("flow-1", "WS-FLOW-1", "流量监测点1", "11", BASE_TIME);
         when(equipmentBaseMapper.selectById("flow-1")).thenReturn(device);
         when(radarDataMapper.selectList(any())).thenReturn(Arrays.asList(
                 radar("WS-FLOW-1", "10", BASE_TIME.minusDays(3)),
@@ -317,9 +328,9 @@ class MonitoringServiceImplTest {
 
     @Test
     void trendQueriesWithOnlyAnEndTimeDoNotBindNullStartTime() {
-        EquipmentBase flowDevice = device("flow-1", "WS-FLOW-1", "流量监测点1", "flow-type", BASE_TIME);
-        EquipmentBase pressureDevice = device("pressure-1", "WS-PR-1", "压力监测点1", "pressure-type", BASE_TIME);
-        EquipmentBase leakageDevice = device("leakage-1", "WS-LK-1", "漏失监测点1", "leakage-type", BASE_TIME);
+        EquipmentBase flowDevice = device("flow-1", "WS-FLOW-1", "流量监测点1", "11", BASE_TIME);
+        EquipmentBase pressureDevice = device("pressure-1", "WS-PR-1", "压力监测点1", "12", BASE_TIME);
+        EquipmentBase leakageDevice = device("leakage-1", "WS-LK-1", "漏失监测点1", "13", BASE_TIME);
         when(equipmentBaseMapper.selectById("flow-1")).thenReturn(flowDevice);
         when(equipmentBaseMapper.selectById("pressure-1")).thenReturn(pressureDevice);
         when(equipmentBaseMapper.selectById("leakage-1")).thenReturn(leakageDevice);
@@ -339,7 +350,7 @@ class MonitoringServiceImplTest {
     @Test
     void requestedPageBeyondMeasurementResultsKeepsTheFilteredTotal() {
         when(equipmentBaseMapper.selectList(any())).thenReturn(Collections.singletonList(
-                device("flow-1", "WS-FLOW-1", "流量监测点1", "flow-type", BASE_TIME)
+                device("flow-1", "WS-FLOW-1", "流量监测点1", "11", BASE_TIME)
         ));
         when(radarDataMapper.selectList(any())).thenReturn(Collections.singletonList(
                 radar("WS-FLOW-1", "10", BASE_TIME)
@@ -352,7 +363,7 @@ class MonitoringServiceImplTest {
     }
 
     private static EquipmentType type(String id, String typeId, String name) {
-        return type(id, typeId, name, "water-root");
+        return type(id, typeId, name, "1");
     }
 
     private static Set<Object> flattenWrapperValues(