Просмотр исходного кода

feat(water): stabilize pipe network statistics (#7)

Kazerin 3 дней назад
Родитель
Сommit
0a5cc990fe

+ 29 - 9
pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/PipeNetworkStatistics/service/impl/PipeNetworkStatisticsServiceImpl.java

@@ -14,6 +14,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.ArrayList;
 import java.util.stream.Collectors;
 
 @Service
@@ -29,10 +30,19 @@ public class PipeNetworkStatisticsServiceImpl implements PipeNetworkStatisticsSe
         Set<String> types = facilityTypes == null || facilityTypes.isEmpty() ? SUPPORTED_TYPES : facilityTypes;
         PipeNetworkStatisticsDashboardDTO dashboard = new PipeNetworkStatisticsDashboardDTO();
         List<com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO> overview = statisticsMapper.selectFacilityOverview(status);
-        dashboard.setFacilityOverview((overview == null ? Collections.<com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO>emptyList() : overview)
-                .stream().filter(item -> types.contains(item.getFacilityType())).collect(Collectors.toList()));
+        List<com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO> filtered = (overview == null ? Collections.<com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO>emptyList() : overview)
+                .stream().filter(item -> types.contains(item.getFacilityType())).collect(Collectors.toList());
+        if (filtered.isEmpty()) {
+            filtered = new ArrayList<>();
+            addZeroOverview(filtered, types, "source", "水源地");
+            addZeroOverview(filtered, types, "plant", "水厂");
+            addZeroOverview(filtered, types, "pumpStation", "泵站");
+            addZeroOverview(filtered, types, "pipe", "供水管网");
+            addZeroOverview(filtered, types, "user", "用水户");
+        }
+        dashboard.setFacilityOverview(filtered);
         if (types.contains("pipe")) {
-            Map<String, Object> result = zeroSafe(statisticsMapper.selectPipeSummary(status));
+            Map<String, Object> result = zeroSafe(statisticsMapper.selectPipeSummary(status), "totalCount");
             result.put("materialDistribution", list(statisticsMapper.selectPipeMaterialDistribution(status)));
             result.put("diameterDistribution", list(statisticsMapper.selectPipeDiameterDistribution(status)));
             result.put("layingYearDistribution", list(statisticsMapper.selectPipeLayingYearDistribution(status)));
@@ -41,19 +51,19 @@ public class PipeNetworkStatisticsServiceImpl implements PipeNetworkStatisticsSe
             dashboard.setPipeNetwork(result);
         }
         if (types.contains("plant")) {
-            Map<String, Object> result = zeroSafe(statisticsMapper.selectWaterPlantSummary(status));
+            Map<String, Object> result = zeroSafe(statisticsMapper.selectWaterPlantSummary(status), "totalCount");
             result.put("capacityUtilization", utilization(result));
             result.put("statusDistribution", list(statisticsMapper.selectStatusDistribution("plant", status)));
             result.put("waterSourceTypeDistribution", list(statisticsMapper.selectWaterPlantSourceTypeDistribution(status)));
             dashboard.setWaterPlant(result);
         }
         if (types.contains("pumpStation")) {
-            Map<String, Object> result = zeroSafe(statisticsMapper.selectPumpStationSummary(status));
+            Map<String, Object> result = zeroSafe(statisticsMapper.selectPumpStationSummary(status), "totalCount");
             result.put("statusDistribution", list(statisticsMapper.selectStatusDistribution("pumpStation", status)));
             dashboard.setPumpStation(result);
         }
         if (types.contains("source")) {
-            Map<String, Object> result = zeroSafe(statisticsMapper.selectWaterSourceSummary(status));
+            Map<String, Object> result = zeroSafe(statisticsMapper.selectWaterSourceSummary(status), "totalCount");
             result.put("statusDistribution", list(statisticsMapper.selectStatusDistribution("source", status)));
             result.put("sourceTypeDistribution", list(statisticsMapper.selectWaterSourceTypeDistribution(status)));
             result.put("qualityDistribution", list(statisticsMapper.selectWaterSourceQualityDistribution(status)));
@@ -61,7 +71,7 @@ public class PipeNetworkStatisticsServiceImpl implements PipeNetworkStatisticsSe
             dashboard.setWaterSource(result);
         }
         if (types.contains("user")) {
-            Map<String, Object> result = zeroSafe(statisticsMapper.selectWaterUserSummary(status));
+            Map<String, Object> result = zeroSafe(statisticsMapper.selectWaterUserSummary(status), "totalCount");
             result.put("statusDistribution", list(statisticsMapper.selectStatusDistribution("user", status)));
             result.put("userTypeDistribution", list(statisticsMapper.selectWaterUserTypeDistribution(status)));
             result.put("consumptionDistribution", list(statisticsMapper.selectWaterUserConsumptionDistribution(status)));
@@ -76,8 +86,18 @@ public class PipeNetworkStatisticsServiceImpl implements PipeNetworkStatisticsSe
         }
     }
 
-    private Map<String, Object> zeroSafe(Map<String, Object> value) {
-        return value == null ? new LinkedHashMap<>() : new LinkedHashMap<>(value);
+    private Map<String, Object> zeroSafe(Map<String, Object> value, String... zeroKeys) {
+        Map<String, Object> result = value == null ? new LinkedHashMap<>() : new LinkedHashMap<>(value);
+        for (String key : zeroKeys) result.putIfAbsent(key, 0L);
+        return result;
+    }
+
+    private void addZeroOverview(List<com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO> target,
+                                 Set<String> types, String type, String label) {
+        if (!types.contains(type)) return;
+        com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO item = new com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO();
+        item.setFacilityType(type); item.setFacilityTypeName(label); item.setTotalCount(0L); item.setNormalCount(0L); item.setAbnormalCount(0L);
+        target.add(item);
     }
 
     private List<MetricItemDTO> list(List<MetricItemDTO> value) {

+ 4 - 4
pipe-network-service/zksy-system/src/main/resources/mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml

@@ -64,13 +64,13 @@
     </select>
     <select id="selectPipeLayingYearDistribution" resultType="com.zksy.WaterSupply.PipeNetworkStatistics.dto.MetricItemDTO">
         SELECT CASE WHEN laying_year IS NULL THEN CAST('未填报' AS VARCHAR)
-          ELSE CONCAT(CAST((laying_year / 10) * 10 AS VARCHAR), '-',
-                      CAST((laying_year / 10) * 10 + 9 AS VARCHAR)) END name,
+          ELSE CONCAT(CAST(FLOOR(laying_year / 10) * 10 AS INTEGER), '-',
+                      CAST(FLOOR(laying_year / 10) * 10 + 9 AS INTEGER)) END name,
           COUNT(*) "value", '条' unit FROM app_user.water_pipe_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         GROUP BY CASE WHEN laying_year IS NULL THEN CAST('未填报' AS VARCHAR)
-          ELSE CONCAT(CAST((laying_year / 10) * 10 AS VARCHAR), '-',
-                      CAST((laying_year / 10) * 10 + 9 AS VARCHAR)) END
+          ELSE CONCAT(CAST(FLOOR(laying_year / 10) * 10 AS INTEGER), '-',
+                      CAST(FLOOR(laying_year / 10) * 10 + 9 AS INTEGER)) END
     </select>
     <select id="selectPipePressureDistribution" resultType="com.zksy.WaterSupply.PipeNetworkStatistics.dto.MetricItemDTO">
         SELECT COALESCE(CAST(pressure_rating AS VARCHAR), '未填报') name, COUNT(*) "value", '条' unit FROM app_user.water_pipe_info WHERE del_flag = '0'

+ 31 - 0
pipe-network-service/zksy-system/src/test/java/com/zksy/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsExportServiceContractTest.java

@@ -0,0 +1,31 @@
+package com.zksy.WaterSupply.PipeNetworkStatistics;
+
+import com.zksy.WaterSupply.PipeNetworkStatistics.dto.PipeNetworkStatisticsDashboardDTO;
+import com.zksy.WaterSupply.PipeNetworkStatistics.service.impl.PipeNetworkStatisticsExportServiceImpl;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class PipeNetworkStatisticsExportServiceContractTest {
+    @Test
+    void exportCreatesTheSixFixedWorksheets() throws Exception {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        new PipeNetworkStatisticsExportServiceImpl().write(output, new PipeNetworkStatisticsDashboardDTO());
+
+        try (Workbook workbook = new XSSFWorkbook(new ByteArrayInputStream(output.toByteArray()))) {
+            List<String> sheetNames = new ArrayList<>();
+            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
+                sheetNames.add(workbook.getSheetName(i));
+            }
+
+            assertEquals(List.of("综合概览", "管网统计", "水厂统计", "泵站统计", "水源地统计", "用水户统计"), sheetNames);
+        }
+    }
+}

+ 45 - 0
pipe-network-service/zksy-system/src/test/java/com/zksy/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsServiceContractTest.java

@@ -0,0 +1,45 @@
+package com.zksy.WaterSupply.PipeNetworkStatistics;
+
+import com.zksy.WaterSupply.PipeNetworkStatistics.mapper.PipeNetworkStatisticsMapper;
+import com.zksy.WaterSupply.PipeNetworkStatistics.service.impl.PipeNetworkStatisticsServiceImpl;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class PipeNetworkStatisticsServiceContractTest {
+    @Mock
+    private PipeNetworkStatisticsMapper mapper;
+
+    @InjectMocks
+    private PipeNetworkStatisticsServiceImpl service;
+
+    @Test
+    void emptyDatabaseStillReturnsStableZeroDashboardSections() {
+        when(mapper.selectFacilityOverview(null)).thenReturn(null);
+        when(mapper.selectPipeSummary(null)).thenReturn(null);
+        when(mapper.selectWaterPlantSummary(null)).thenReturn(null);
+        when(mapper.selectPumpStationSummary(null)).thenReturn(null);
+        when(mapper.selectWaterSourceSummary(null)).thenReturn(null);
+        when(mapper.selectWaterUserSummary(null)).thenReturn(null);
+
+        var result = service.getDashboard(null, null);
+
+        assertEquals(5, result.getFacilityOverview().size());
+        assertEquals(0L, result.getFacilityOverview().get(0).getTotalCount());
+        assertNotNull(result.getPipeNetwork());
+        assertEquals(0L, result.getPipeNetwork().get("totalCount"));
+        assertEquals(0L, result.getWaterPlant().get("totalCount"));
+        assertEquals(0L, result.getPumpStation().get("totalCount"));
+        assertEquals(0L, result.getWaterSource().get("totalCount"));
+        assertEquals(0L, result.getWaterUser().get("totalCount"));
+    }
+}