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

fix(water): classify facility statistics statuses (#7)

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

+ 2 - 2
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsController.java

@@ -37,7 +37,7 @@ public class PipeNetworkStatisticsController {
             notes = "请求参数为可选查询条件。响应 data 包含 facilityOverview、pipeNetwork、waterPlant、pumpStation、waterSource、waterUser 六个区块;分组项结构为 {name, value, unit}。")
     @PreAuthorize("@ss.hasPermi('waterSupply:pipeNetwork:statistics')")
     public AjaxResult dashboard(
-            @ApiParam(value = "设施状态:0正常、1/2异常;不传查询全部", example = "0")
+            @ApiParam(value = "设施状态:0正常;1/2按设施类型分别表示异常、停产、故障停运、停用、欠费、检修中;不传查询全部", example = "0")
             @RequestParam(required = false) String status,
             @ApiParam(value = "设施类型,逗号分隔:source、plant、pumpStation、pipe、user;不传查询全部", example = "plant,pipe")
             @RequestParam(required = false) String facilityTypes) {
@@ -55,7 +55,7 @@ public class PipeNetworkStatisticsController {
     @Log(title = "管网数据统计分析", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('waterSupply:pipeNetwork:statistics:export')")
     public void export(HttpServletResponse response,
-                       @ApiParam(value = "设施状态:0正常、1/2异常;不传查询全部", example = "0")
+                       @ApiParam(value = "设施状态:0正常;1/2按设施类型分别表示异常、停产、故障停运、停用、欠费、检修中;不传查询全部", example = "0")
                        @RequestParam(required = false) String status,
                        @ApiParam(value = "设施类型,逗号分隔:source、plant、pumpStation、pipe、user;不传查询全部", example = "source,user")
                        @RequestParam(required = false) String facilityTypes) throws IOException {

+ 14 - 0
pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsControllerTerminologyTest.java

@@ -1,6 +1,7 @@
 package com.zksy.web.controller.WaterSupply.PipeNetworkStatistics;
 
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import org.junit.jupiter.api.Test;
 
 import javax.servlet.http.HttpServletResponse;
@@ -20,4 +21,17 @@ class PipeNetworkStatisticsControllerTerminologyTest {
         assertTrue(operation.notes().contains("用水户统计"));
         assertFalse(operation.notes().contains("大用水户统计"));
     }
+
+    @Test
+    void statusDescriptionsUseFacilitySpecificTerminology() throws Exception {
+        for (Method method : PipeNetworkStatisticsController.class.getMethods()) {
+            for (java.lang.reflect.Parameter parameter : method.getParameters()) {
+                ApiParam annotation = parameter.getAnnotation(ApiParam.class);
+                if (annotation != null && annotation.value().startsWith("设施状态")) {
+                    assertFalse(annotation.value().contains("1/2异常"));
+                    assertTrue(annotation.value().contains("按设施类型"));
+                }
+            }
+        }
+    }
 }

+ 2 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/PipeNetworkStatistics/dto/FacilityStatisticItemDTO.java

@@ -9,4 +9,6 @@ public class FacilityStatisticItemDTO {
     private Long totalCount;
     private Long normalCount;
     private Long abnormalCount;
+    private Long warningCount;
+    private Long unknownCount;
 }

+ 39 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/PipeNetworkStatistics/service/impl/PipeNetworkStatisticsExportServiceImpl.java

@@ -1,5 +1,6 @@
 package com.zksy.WaterSupply.PipeNetworkStatistics.service.impl;
 
+import com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO;
 import com.zksy.WaterSupply.PipeNetworkStatistics.dto.MetricItemDTO;
 import com.zksy.WaterSupply.PipeNetworkStatistics.dto.PipeNetworkStatisticsDashboardDTO;
 import com.zksy.WaterSupply.PipeNetworkStatistics.service.PipeNetworkStatisticsExportService;
@@ -42,10 +43,48 @@ public class PipeNetworkStatisticsExportServiceImpl implements PipeNetworkStatis
                 row.createCell(1).setCellValue(item.getFacilityTypeName());
                 row.createCell(2).setCellValue(item.getTotalCount() == null ? 0 : item.getTotalCount());
                 row.createCell(3).setCellValue("项");
+
+                addOverviewRow(sheet, rowIndex++, item, "正常", item.getNormalCount());
+                addOverviewRow(sheet, rowIndex++, item, abnormalStatusLabel(item.getFacilityType()), item.getAbnormalCount());
+                if (hasWarningStatus(item.getFacilityType())) {
+                    addOverviewRow(sheet, rowIndex++, item, warningStatusLabel(item.getFacilityType()), item.getWarningCount());
+                }
+                addOverviewRow(sheet, rowIndex++, item, "未知", item.getUnknownCount());
             }
         }
     }
 
+    private boolean hasWarningStatus(String facilityType) {
+        return "pumpStation".equals(facilityType) || "user".equals(facilityType);
+    }
+
+    private String abnormalStatusLabel(String facilityType) {
+        switch (facilityType) {
+            case "plant":
+                return "停产";
+            case "pumpStation":
+                return "故障停运";
+            case "pipe":
+                return "停用";
+            case "user":
+                return "停用";
+            default:
+                return "异常";
+        }
+    }
+
+    private String warningStatusLabel(String facilityType) {
+        return "pumpStation".equals(facilityType) ? "检修中" : "欠费";
+    }
+
+    private void addOverviewRow(Sheet sheet, int rowIndex, FacilityStatisticItemDTO item, String label, Long count) {
+        Row row = sheet.createRow(rowIndex);
+        row.createCell(0).setCellValue("状态统计");
+        row.createCell(1).setCellValue(item.getFacilityTypeName() + "-" + label);
+        row.createCell(2).setCellValue(count == null ? 0 : count);
+        row.createCell(3).setCellValue("项");
+    }
+
     private void writeMapSheet(Sheet sheet, Map<String, Object> values) {
         header(sheet);
         if (values == null) return;

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

@@ -97,6 +97,7 @@ public class PipeNetworkStatisticsServiceImpl implements PipeNetworkStatisticsSe
         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);
+        item.setWarningCount(0L); item.setUnknownCount(0L);
         target.add(item);
     }
 

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

@@ -4,23 +4,35 @@
     <select id="selectFacilityOverview" resultType="com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO">
         SELECT 'source' facility_type, '水源地' facility_type_name, COUNT(*) total_count,
                COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0) normal_count,
-               COALESCE(SUM(CASE WHEN status IS NOT NULL AND status &lt;&gt; '0' THEN 1 ELSE 0 END), 0) abnormal_count
+               COALESCE(SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END), 0) abnormal_count,
+               0 warning_count,
+               COALESCE(SUM(CASE WHEN status IS NULL OR status NOT IN ('0', '1') THEN 1 ELSE 0 END), 0) unknown_count
         FROM app_user.water_source_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         UNION ALL
-        SELECT 'plant', '水厂', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN status IS NOT NULL AND status &lt;&gt; '0' THEN 1 ELSE 0 END), 0)
+        SELECT 'plant', '水厂', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END), 0), 0,
+               COALESCE(SUM(CASE WHEN status IS NULL OR status NOT IN ('0', '1') THEN 1 ELSE 0 END), 0)
         FROM app_user.water_plant_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         UNION ALL
-        SELECT 'pumpStation', '泵站', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN status IS NOT NULL AND status &lt;&gt; '0' THEN 1 ELSE 0 END), 0)
+        SELECT 'pumpStation', '泵站', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status = '2' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status IS NULL OR status NOT IN ('0', '1', '2') THEN 1 ELSE 0 END), 0)
         FROM app_user.water_pump_station WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         UNION ALL
-        SELECT 'pipe', '供水管网', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN status IS NOT NULL AND status &lt;&gt; '0' THEN 1 ELSE 0 END), 0)
+        SELECT 'pipe', '供水管网', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END), 0), 0,
+               COALESCE(SUM(CASE WHEN status IS NULL OR status NOT IN ('0', '1') THEN 1 ELSE 0 END), 0)
         FROM app_user.water_pipe_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         UNION ALL
-        SELECT 'user', '用水户', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN status IS NOT NULL AND status &lt;&gt; '0' THEN 1 ELSE 0 END), 0)
+        SELECT 'user', '用水户', COUNT(*), COALESCE(SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status = '2' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END), 0),
+               COALESCE(SUM(CASE WHEN status IS NULL OR status NOT IN ('0', '1', '2') THEN 1 ELSE 0 END), 0)
         FROM app_user.water_user_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
     </select>
@@ -78,7 +90,7 @@
     </select>
 
     <select id="selectStatusDistribution" resultType="com.zksy.WaterSupply.PipeNetworkStatistics.dto.MetricItemDTO">
-        SELECT COALESCE(status, '未填报') name, COUNT(*) "value", '条' unit FROM
+        SELECT COALESCE(status, '未') name, COUNT(*) "value", '条' unit FROM
         <choose><when test="tableType == 'pipe'">app_user.water_pipe_info</when><when test="tableType == 'plant'">app_user.water_plant_info</when><when test="tableType == 'pumpStation'">app_user.water_pump_station</when><when test="tableType == 'source'">app_user.water_source_info</when><otherwise>app_user.water_user_info</otherwise></choose>
         WHERE del_flag = '0' <if test="status != null and status != ''">AND status = #{status}</if> GROUP BY status
     </select>

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

@@ -1,17 +1,21 @@
 package com.zksy.WaterSupply.PipeNetworkStatistics;
 
 import com.zksy.WaterSupply.PipeNetworkStatistics.dto.PipeNetworkStatisticsDashboardDTO;
+import com.zksy.WaterSupply.PipeNetworkStatistics.dto.FacilityStatisticItemDTO;
 import com.zksy.WaterSupply.PipeNetworkStatistics.service.impl.PipeNetworkStatisticsExportServiceImpl;
 import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.Sheet;
 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.Arrays;
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
 
 class PipeNetworkStatisticsExportServiceContractTest {
     @Test
@@ -28,4 +32,55 @@ class PipeNetworkStatisticsExportServiceContractTest {
             assertEquals(List.of("综合概览", "管网统计", "水厂统计", "泵站统计", "水源地统计", "用水户统计"), sheetNames);
         }
     }
+
+    @Test
+    void exportUsesFacilitySpecificStatusLabels() throws Exception {
+        PipeNetworkStatisticsDashboardDTO dashboard = new PipeNetworkStatisticsDashboardDTO();
+        dashboard.setFacilityOverview(Arrays.asList(
+                facility("source", "水源地", 3L, 2L, 1L, 0L, 0L),
+                facility("plant", "水厂", 3L, 2L, 1L, 0L, 0L),
+                facility("pumpStation", "泵站", 4L, 2L, 1L, 1L, 0L),
+                facility("pipe", "供水管网", 3L, 2L, 1L, 0L, 0L),
+                facility("user", "用水户", 4L, 2L, 1L, 1L, 0L)
+        ));
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        new PipeNetworkStatisticsExportServiceImpl().write(output, dashboard);
+
+        try (Workbook workbook = new XSSFWorkbook(new ByteArrayInputStream(output.toByteArray()))) {
+            var sheet = workbook.getSheet("综合概览");
+            assertOverviewRow(sheet, "水源地-正常", 2D);
+            assertOverviewRow(sheet, "水源地-异常", 1D);
+            assertOverviewRow(sheet, "水厂-停产", 1D);
+            assertOverviewRow(sheet, "泵站-故障停运", 1D);
+            assertOverviewRow(sheet, "泵站-检修中", 1D);
+            assertOverviewRow(sheet, "供水管网-停用", 1D);
+            assertOverviewRow(sheet, "用水户-欠费", 1D);
+            assertOverviewRow(sheet, "用水户-停用", 1D);
+        }
+    }
+
+    private FacilityStatisticItemDTO facility(
+            String type, String name, Long total, Long normal, Long abnormal, Long warning, Long unknown
+    ) {
+        FacilityStatisticItemDTO item = new FacilityStatisticItemDTO();
+        item.setFacilityType(type);
+        item.setFacilityTypeName(name);
+        item.setTotalCount(total);
+        item.setNormalCount(normal);
+        item.setAbnormalCount(abnormal);
+        item.setWarningCount(warning);
+        item.setUnknownCount(unknown);
+        return item;
+    }
+
+    private void assertOverviewRow(Sheet sheet, String label, double expectedValue) {
+        for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
+            var row = sheet.getRow(rowIndex);
+            if (row != null && label.equals(row.getCell(1).getStringCellValue())) {
+                assertEquals(expectedValue, row.getCell(2).getNumericCellValue());
+                return;
+            }
+        }
+        fail("Missing export status row: " + label);
+    }
 }

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

@@ -8,6 +8,8 @@ import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Map;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -35,6 +37,10 @@ class PipeNetworkStatisticsServiceContractTest {
 
         assertEquals(5, result.getFacilityOverview().size());
         assertEquals(0L, result.getFacilityOverview().get(0).getTotalCount());
+        assertEquals(0L, result.getFacilityOverview().get(0).getNormalCount());
+        assertEquals(0L, result.getFacilityOverview().get(0).getAbnormalCount());
+        assertEquals(0L, result.getFacilityOverview().get(0).getWarningCount());
+        assertEquals(0L, result.getFacilityOverview().get(0).getUnknownCount());
         assertNotNull(result.getPipeNetwork());
         assertEquals(0L, result.getPipeNetwork().get("totalCount"));
         assertEquals(0L, result.getWaterPlant().get("totalCount"));
@@ -42,4 +48,25 @@ class PipeNetworkStatisticsServiceContractTest {
         assertEquals(0L, result.getWaterSource().get("totalCount"));
         assertEquals(0L, result.getWaterUser().get("totalCount"));
     }
+
+    @Test
+    void facilityOverviewCountsUnexpectedStatusValuesAsUnknown() throws Exception {
+        String mapper = Files.readString(Path.of(
+                "src/main/resources/mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml"
+        ));
+
+        assertEquals(3, countOccurrences(mapper, "status IS NULL OR status NOT IN ('0', '1')"));
+        assertEquals(2, countOccurrences(mapper, "status IS NULL OR status NOT IN ('0', '1', '2')"));
+        assertEquals(1, countOccurrences(mapper, "COALESCE(status, '未知') name"));
+    }
+
+    private int countOccurrences(String source, String token) {
+        int count = 0;
+        int index = 0;
+        while ((index = source.indexOf(token, index)) >= 0) {
+            count++;
+            index += token.length();
+        }
+        return count;
+    }
 }