Pārlūkot izejas kodu

fix(water-supply): 统一用水户领域称谓

Kazerin 1 nedēļu atpakaļ
vecāks
revīzija
3f5e1e8612
12 mainītis faili ar 196 papildinājumiem un 30 dzēšanām
  1. 4 0
      pipe-network-service/CONTEXT.md
  2. 13 7
      pipe-network-service/sql/water_supply_facility_test_data.sql
  3. 1 1
      pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsController.java
  4. 9 9
      pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/WaterSupply/WaterUserInfo/WaterUserInfoController.java
  5. 23 0
      pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsControllerTerminologyTest.java
  6. 1 1
      pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/PipeNetworkStatistics/service/impl/PipeNetworkStatisticsExportServiceImpl.java
  7. 1 1
      pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/WaterSupplyGisMap/service/impl/WaterSupplyGisMapServiceImpl.java
  8. 6 6
      pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/WaterUserInfo/domain/WaterUserInfo.java
  9. 3 3
      pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/export/WaterUserExportDTO.java
  10. 1 1
      pipe-network-service/zksy-system/src/main/resources/mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml
  11. 1 1
      pipe-network-service/zksy-system/src/main/resources/mapper/WaterSupply/WaterSupplyGisMap/WaterSupplyGisMapMapper.xml
  12. 133 0
      pipe-network-service/zksy-system/src/test/java/com/zksy/WaterSupply/WaterUserTerminologyTest.java

+ 4 - 0
pipe-network-service/CONTEXT.md

@@ -28,6 +28,10 @@ _Avoid_:管网、管道(指单条设施时)
 接受供水服务的居民、工业、商业或行政事业主体。
 接受供水服务的居民、工业、商业或行政事业主体。
 _Avoid_:大用水户(除非明确指满足特定用水量或重要性标准的子集)、用户
 _Avoid_:大用水户(除非明确指满足特定用水量或重要性标准的子集)、用户
 
 
+兼容映射:既有设施类型编码 `user`、接口区块 `waterUser`、Java 类型 `WaterUserInfo`、
+持久化表 `water_user_info` 及其 `user_*` 字段均表示“用水户”,覆盖居民、工业、商业和
+行政事业等全部类型。为保持现有接口与数据兼容,这些技术标识继续保留,不表示“大用水户”子集。
+
 ## 运行监测
 ## 运行监测
 
 
 **监测设备**:
 **监测设备**:

+ 13 - 7
pipe-network-service/sql/water_supply_facility_test_data.sql

@@ -110,7 +110,7 @@ VALUES
      113.32000000, 23.16000000, NULL, NULL);
      113.32000000, 23.16000000, NULL, NULL);
 
 
 -- ------------------------------------------------------------
 -- ------------------------------------------------------------
--- 5. 大用水户:2 个坐标完整 + 1 个缺失坐标
+-- 5. 用水户:居民、工业、商业、行政事业均参与,4 个坐标完整 + 1 个缺失坐标
 -- ------------------------------------------------------------
 -- ------------------------------------------------------------
 INSERT INTO app_user.water_user_info
 INSERT INTO app_user.water_user_info
     (user_code, user_name, user_type, address, contact_person,
     (user_code, user_name, user_type, address, contact_person,
@@ -120,12 +120,18 @@ INSERT INTO app_user.water_user_info
 VALUES
 VALUES
     ('GIS-TEST-U-001', 'GIS测试用水户-工业园', '工业', '测试工业园1号', '测试联系人1',
     ('GIS-TEST-U-001', 'GIS测试用水户-工业园', '工业', '测试工业园1号', '测试联系人1',
      '13800000005', 'GIS-METER-001', 1000.00, 52000.00, 51000.00, '0',
      '13800000005', 'GIS-METER-001', 1000.00, 52000.00, 51000.00, '0',
-     'GIS接口测试-坐标完整-大用水量', '0', 'test', CURRENT_TIMESTAMP, 113.32000000, 23.16000000),
-    ('GIS-TEST-U-002', 'GIS测试用水户-医院', '公共机构', '测试医院2号', '测试联系人2',
+     'GIS接口测试-坐标完整-工业', '0', 'test', CURRENT_TIMESTAMP, 113.32000000, 23.16000000),
+    ('GIS-TEST-U-002', 'GIS测试用水户-医院', '行政事业', '测试医院2号', '测试联系人2',
      '13800000006', 'GIS-METER-002', 500.00, 12500.00, 12000.00, '1',
      '13800000006', 'GIS-METER-002', 500.00, 12500.00, 12000.00, '1',
-     'GIS接口测试-坐标完整-异常', '0', 'test', CURRENT_TIMESTAMP, 113.33000000, 23.17000000),
-    ('GIS-TEST-U-003', 'GIS测试用水户-待测', '商业', '测试商业街3号', '测试联系人3',
-     '13800000007', 'GIS-METER-003', 100.00, 800.00, NULL, NULL,
+     'GIS接口测试-坐标完整-行政事业', '0', 'test', CURRENT_TIMESTAMP, 113.33000000, 23.17000000),
+    ('GIS-TEST-U-003', 'GIS测试用水户-商业街', '商业', '测试商业街3号', '测试联系人3',
+     '13800000007', 'GIS-METER-003', 100.00, 800.00, 700.00, '0',
+     'GIS接口测试-坐标完整-商业', '0', 'test', CURRENT_TIMESTAMP, 113.34000000, 23.18000000),
+    ('GIS-TEST-U-004', 'GIS测试用水户-居民', '居民', '测试小区4号', '测试联系人4',
+     '13800000008', 'GIS-METER-004', 10.00, 120.00, 110.00, '0',
+     'GIS接口测试-坐标完整-居民', '0', 'test', CURRENT_TIMESTAMP, 113.35000000, 23.19000000),
+    ('GIS-TEST-U-005', 'GIS测试用水户-缺失坐标', '商业', '测试商业街5号', '测试联系人5',
+     '13800000009', 'GIS-METER-005', 100.00, 800.00, NULL, NULL,
      'GIS接口测试-缺失坐标-概览计数', '0', 'test', CURRENT_TIMESTAMP, NULL, NULL);
      'GIS接口测试-缺失坐标-概览计数', '0', 'test', CURRENT_TIMESTAMP, NULL, NULL);
 
 
 COMMIT;
 COMMIT;
@@ -133,7 +139,7 @@ COMMIT;
 -- ------------------------------------------------------------
 -- ------------------------------------------------------------
 -- 6. 验证输出
 -- 6. 验证输出
 -- ------------------------------------------------------------
 -- ------------------------------------------------------------
--- 预期:source=3/完整2,plant=2/完整1,pumpStation=2/完整1,pipe=4/完整3,user=3/完整2
+-- 预期:source=3/完整2,plant=2/完整1,pumpStation=2/完整1,pipe=4/完整3,user=5/完整4
 SELECT 'source' facility_type, COUNT(*) total_count,
 SELECT 'source' facility_type, COUNT(*) total_count,
        COALESCE(SUM(CASE WHEN longitude IS NOT NULL AND latitude IS NOT NULL THEN 1 ELSE 0 END), 0) geo_complete_count
        COALESCE(SUM(CASE WHEN longitude IS NOT NULL AND latitude IS NOT NULL THEN 1 ELSE 0 END), 0) geo_complete_count
   FROM app_user.water_source_info WHERE source_id LIKE 'GIS-TEST-%'
   FROM app_user.water_source_info WHERE source_id LIKE 'GIS-TEST-%'

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

@@ -51,7 +51,7 @@ public class PipeNetworkStatisticsController {
 
 
     @GetMapping("/export")
     @GetMapping("/export")
     @ApiOperation(value = "供水管网-管网数据统计分析-导出统计 Excel",
     @ApiOperation(value = "供水管网-管网数据统计分析-导出统计 Excel",
-            notes = "请求参数与综合统计仪表盘一致。响应为文件流,文件名为管网数据统计分析.xlsx,包含综合概览、管网统计、水厂统计、泵站统计、水源地统计、用水户统计六个工作表。")
+            notes = "请求参数与综合统计仪表盘一致。响应为文件流,文件名为管网数据统计分析.xlsx,包含综合概览、管网统计、水厂统计、泵站统计、水源地统计、用水户统计六个工作表。")
     @Log(title = "管网数据统计分析", businessType = BusinessType.EXPORT)
     @Log(title = "管网数据统计分析", businessType = BusinessType.EXPORT)
     @PreAuthorize("@ss.hasPermi('waterSupply:pipeNetwork:statistics:export')")
     @PreAuthorize("@ss.hasPermi('waterSupply:pipeNetwork:statistics:export')")
     public void export(HttpServletResponse response,
     public void export(HttpServletResponse response,

+ 9 - 9
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/WaterSupply/WaterUserInfo/WaterUserInfoController.java

@@ -34,7 +34,7 @@ public class WaterUserInfoController {
 
 
     // -------------------------- 基础CRUD接口 --------------------------
     // -------------------------- 基础CRUD接口 --------------------------
     @GetMapping("/page")
     @GetMapping("/page")
-    @ApiOperation(value = "分页查询用水户数据", notes = "支持按用户编号、名称、状态、用户类型、时间范围模糊查询")
+    @ApiOperation(value = "分页查询用水户数据", notes = "支持按用户编号、名称、状态、类型、时间范围模糊查询")
     @ApiResponses({
     @ApiResponses({
             @ApiResponse(code = 200, message = "查询成功", response = AjaxResult.class),
             @ApiResponse(code = 200, message = "查询成功", response = AjaxResult.class),
             @ApiResponse(code = 500, message = "服务器内部错误,查询失败", response = AjaxResult.class)
             @ApiResponse(code = 500, message = "服务器内部错误,查询失败", response = AjaxResult.class)
@@ -42,10 +42,10 @@ public class WaterUserInfoController {
     public AjaxResult queryPage(
     public AjaxResult queryPage(
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer pageNum,
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer pageNum,
             @ApiParam(value = "每页大小", defaultValue = "10") @RequestParam(defaultValue = "10") Integer pageSize,
             @ApiParam(value = "每页大小", defaultValue = "10") @RequestParam(defaultValue = "10") Integer pageSize,
-            @ApiParam(value = "用户编号") @RequestParam(required = false) String userCode,
-            @ApiParam(value = "用户名称") @RequestParam(required = false) String userName,
-            @ApiParam(value = "用户状态(0正常 1欠费 2停用)") @RequestParam(required = false) String status,
-            @ApiParam(value = "用户类型(居民/工业/商业/行政事业)") @RequestParam(required = false) String userType,
+            @ApiParam(value = "用户编号") @RequestParam(required = false) String userCode,
+            @ApiParam(value = "用户名称") @RequestParam(required = false) String userName,
+            @ApiParam(value = "用户状态(0正常 1欠费 2停用)") @RequestParam(required = false) String status,
+            @ApiParam(value = "用户类型(居民/工业/商业/行政事业)") @RequestParam(required = false) String userType,
             @ApiParam(value = "开始时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-01-01 00:00:00") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
             @ApiParam(value = "开始时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-01-01 00:00:00") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
             @ApiParam(value = "结束时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-12-31 23:59:59") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
             @ApiParam(value = "结束时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-12-31 23:59:59") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
         try {
         try {
@@ -160,9 +160,9 @@ public class WaterUserInfoController {
     public AjaxResult recycleList(
     public AjaxResult recycleList(
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer pageNum,
             @ApiParam(value = "页码", defaultValue = "1") @RequestParam(defaultValue = "1") Integer pageNum,
             @ApiParam(value = "每页大小", defaultValue = "10") @RequestParam(defaultValue = "10") Integer pageSize,
             @ApiParam(value = "每页大小", defaultValue = "10") @RequestParam(defaultValue = "10") Integer pageSize,
-            @ApiParam(value = "用户编号") @RequestParam(required = false) String userCode,
-            @ApiParam(value = "用户名称") @RequestParam(required = false) String userName,
-            @ApiParam(value = "用户状态(0正常 1欠费 2停用)") @RequestParam(required = false) String status,
+            @ApiParam(value = "用户编号") @RequestParam(required = false) String userCode,
+            @ApiParam(value = "用户名称") @RequestParam(required = false) String userName,
+            @ApiParam(value = "用户状态(0正常 1欠费 2停用)") @RequestParam(required = false) String status,
             @ApiParam(value = "开始时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-01-01 00:00:00") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
             @ApiParam(value = "开始时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-01-01 00:00:00") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
             @ApiParam(value = "结束时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-12-31 23:59:59") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
             @ApiParam(value = "结束时间(格式:yyyy-MM-dd HH:mm:ss)", example = "2025-12-31 23:59:59") @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {
         try {
         try {
@@ -223,4 +223,4 @@ public class WaterUserInfoController {
             return AjaxResult.error("彻底删除失败:" + e.getMessage());
             return AjaxResult.error("彻底删除失败:" + e.getMessage());
         }
         }
     }
     }
-}
+}

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

@@ -0,0 +1,23 @@
+package com.zksy.web.controller.WaterSupply.PipeNetworkStatistics;
+
+import io.swagger.annotations.ApiOperation;
+import org.junit.jupiter.api.Test;
+
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class PipeNetworkStatisticsControllerTerminologyTest {
+
+    @Test
+    void exportSwaggerDescriptionUsesUnifiedWaterUserWorksheetName() throws Exception {
+        Method export = PipeNetworkStatisticsController.class.getMethod(
+                "export", HttpServletResponse.class, String.class, String.class);
+        ApiOperation operation = export.getAnnotation(ApiOperation.class);
+
+        assertTrue(operation.notes().contains("用水户统计"));
+        assertFalse(operation.notes().contains("大用水户统计"));
+    }
+}

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

@@ -27,7 +27,7 @@ public class PipeNetworkStatisticsExportServiceImpl implements PipeNetworkStatis
             writeMapSheet(workbook.createSheet("水厂统计"), dashboard.getWaterPlant());
             writeMapSheet(workbook.createSheet("水厂统计"), dashboard.getWaterPlant());
             writeMapSheet(workbook.createSheet("泵站统计"), dashboard.getPumpStation());
             writeMapSheet(workbook.createSheet("泵站统计"), dashboard.getPumpStation());
             writeMapSheet(workbook.createSheet("水源地统计"), dashboard.getWaterSource());
             writeMapSheet(workbook.createSheet("水源地统计"), dashboard.getWaterSource());
-            writeMapSheet(workbook.createSheet("用水户统计"), dashboard.getWaterUser());
+            writeMapSheet(workbook.createSheet("用水户统计"), dashboard.getWaterUser());
             workbook.write(outputStream);
             workbook.write(outputStream);
         }
         }
     }
     }

+ 1 - 1
pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/WaterSupplyGisMap/service/impl/WaterSupplyGisMapServiceImpl.java

@@ -25,7 +25,7 @@ import java.util.Set;
 @Service
 @Service
 public class WaterSupplyGisMapServiceImpl implements WaterSupplyGisMapService {
 public class WaterSupplyGisMapServiceImpl implements WaterSupplyGisMapService {
     private static final Set<String> SUPPORTED_TYPES = Set.of("source", "plant", "pumpStation", "pipe", "user");
     private static final Set<String> SUPPORTED_TYPES = Set.of("source", "plant", "pumpStation", "pipe", "user");
-    private static final Map<String, String> TYPE_NAMES = Map.of("source", "水源地", "plant", "水厂", "pumpStation", "泵站", "pipe", "供水管网", "user", "用水户");
+    private static final Map<String, String> TYPE_NAMES = Map.of("source", "水源地", "plant", "水厂", "pumpStation", "泵站", "pipe", "供水管网", "user", "用水户");
 
 
     @Resource private WaterSupplyGisMapMapper mapper;
     @Resource private WaterSupplyGisMapMapper mapper;
     @Resource private IWaterSourceInfoService sourceService;
     @Resource private IWaterSourceInfoService sourceService;

+ 6 - 6
pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/WaterUserInfo/domain/WaterUserInfo.java

@@ -34,7 +34,7 @@ public class WaterUserInfo {
     private Long id;
     private Long id;
 
 
     @ApiModelProperty(
     @ApiModelProperty(
-            value = "用户编号",
+            value = "用户编号",
             example = "USER_XX",
             example = "USER_XX",
             required = true,
             required = true,
             position = 2
             position = 2
@@ -42,15 +42,15 @@ public class WaterUserInfo {
     private String userCode;
     private String userCode;
 
 
     @ApiModelProperty(
     @ApiModelProperty(
-            value = "用户名称",
-            example = "XX用户",
+            value = "用户名称",
+            example = "XX用户",
             required = true,
             required = true,
             position = 3
             position = 3
     )
     )
     private String userName;
     private String userName;
 
 
     @ApiModelProperty(
     @ApiModelProperty(
-            value = "用户类型",
+            value = "用户类型",
             example = "居民",
             example = "居民",
             position = 4,
             position = 4,
             notes = "居民/工业/商业/行政事业"
             notes = "居民/工业/商业/行政事业"
@@ -116,7 +116,7 @@ public class WaterUserInfo {
     private BigDecimal annualWaterConsumption;
     private BigDecimal annualWaterConsumption;
 
 
     @ApiModelProperty(
     @ApiModelProperty(
-            value = "用户状态",
+            value = "用户状态",
             example = "0",
             example = "0",
             allowableValues = "0,1,2",
             allowableValues = "0,1,2",
             position = 12,
             position = 12,
@@ -126,7 +126,7 @@ public class WaterUserInfo {
 
 
     @ApiModelProperty(
     @ApiModelProperty(
             value = "备注",
             value = "备注",
-            example = "XX区域重要用水户",
+            example = "用水户补充说明",
             position = 13
             position = 13
     )
     )
     private String remark;
     private String remark;

+ 3 - 3
pipe-network-service/zksy-system/src/main/java/com/zksy/WaterSupply/export/WaterUserExportDTO.java

@@ -8,9 +8,9 @@ import java.math.BigDecimal;
 
 
 @Data
 @Data
 public class WaterUserExportDTO {
 public class WaterUserExportDTO {
-    @Excel(name = "用户编号") private String userCode;
-    @Excel(name = "用户名称") private String userName;
-    @Excel(name = "用户类型") private String userType;
+    @Excel(name = "用户编号") private String userCode;
+    @Excel(name = "用户名称") private String userName;
+    @Excel(name = "用户类型") private String userType;
     @Excel(name = "地址") private String address;
     @Excel(name = "地址") private String address;
     @Excel(name = "年用水量") private BigDecimal annualWaterConsumption;
     @Excel(name = "年用水量") private BigDecimal annualWaterConsumption;
     @Excel(name = "状态") private String status;
     @Excel(name = "状态") private String status;

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

@@ -20,7 +20,7 @@
         FROM app_user.water_pipe_info WHERE del_flag = '0'
         FROM app_user.water_pipe_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         <if test="status != null and status != ''">AND status = #{status}</if>
         UNION ALL
         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 IS NOT NULL AND status &lt;&gt; '0' THEN 1 ELSE 0 END), 0)
         FROM app_user.water_user_info WHERE del_flag = '0'
         FROM app_user.water_user_info WHERE del_flag = '0'
         <if test="status != null and status != ''">AND status = #{status}</if>
         <if test="status != null and status != ''">AND status = #{status}</if>
     </select>
     </select>

+ 1 - 1
pipe-network-service/zksy-system/src/main/resources/mapper/WaterSupply/WaterSupplyGisMap/WaterSupplyGisMapMapper.xml

@@ -39,7 +39,7 @@
         SELECT 'pipe', '供水管网', COUNT(*), COALESCE(SUM(CASE WHEN start_longitude IS NOT NULL AND start_latitude IS NOT NULL AND end_longitude IS NOT NULL AND end_latitude IS NOT NULL THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN start_longitude IS NULL OR start_latitude IS NULL OR end_longitude IS NULL OR end_latitude IS NULL THEN 1 ELSE 0 END), 0)
         SELECT 'pipe', '供水管网', COUNT(*), COALESCE(SUM(CASE WHEN start_longitude IS NOT NULL AND start_latitude IS NOT NULL AND end_longitude IS NOT NULL AND end_latitude IS NOT NULL THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN start_longitude IS NULL OR start_latitude IS NULL OR end_longitude IS NULL OR end_latitude IS NULL THEN 1 ELSE 0 END), 0)
         FROM app_user.water_pipe_info WHERE del_flag = '0'
         FROM app_user.water_pipe_info WHERE del_flag = '0'
         UNION ALL
         UNION ALL
-        SELECT 'user', '用水户', COUNT(*), COALESCE(SUM(CASE WHEN longitude IS NOT NULL AND latitude IS NOT NULL THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN longitude IS NULL OR latitude IS NULL THEN 1 ELSE 0 END), 0)
+        SELECT 'user', '用水户', COUNT(*), COALESCE(SUM(CASE WHEN longitude IS NOT NULL AND latitude IS NOT NULL THEN 1 ELSE 0 END), 0), COALESCE(SUM(CASE WHEN longitude IS NULL OR latitude IS NULL THEN 1 ELSE 0 END), 0)
         FROM app_user.water_user_info WHERE del_flag = '0'
         FROM app_user.water_user_info WHERE del_flag = '0'
     </select>
     </select>
 </mapper>
 </mapper>

+ 133 - 0
pipe-network-service/zksy-system/src/test/java/com/zksy/WaterSupply/WaterUserTerminologyTest.java

@@ -0,0 +1,133 @@
+package com.zksy.WaterSupply;
+
+import com.zksy.WaterSupply.PipeNetworkStatistics.dto.PipeNetworkStatisticsDashboardDTO;
+import com.zksy.WaterSupply.PipeNetworkStatistics.mapper.PipeNetworkStatisticsMapper;
+import com.zksy.WaterSupply.PipeNetworkStatistics.service.impl.PipeNetworkStatisticsExportServiceImpl;
+import com.zksy.WaterSupply.WaterSupplyGisMap.dto.GisFeatureCollectionDTO;
+import com.zksy.WaterSupply.WaterSupplyGisMap.mapper.WaterSupplyGisMapMapper;
+import com.zksy.WaterSupply.WaterSupplyGisMap.service.impl.WaterSupplyGisMapServiceImpl;
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.Configuration;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+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.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class WaterUserTerminologyTest {
+
+    @Mock
+    private WaterSupplyGisMapMapper gisMapper;
+
+    @InjectMocks
+    private WaterSupplyGisMapServiceImpl gisService;
+
+    @Test
+    void gisUserLayerReturnsEveryWaterUserCategoryWithUnifiedName() {
+        when(gisMapper.selectUserFeatures()).thenReturn(List.of(
+                userRow(1L, "RESIDENT", "居民用水户"),
+                userRow(2L, "INDUSTRIAL", "工业用水户"),
+                userRow(3L, "COMMERCIAL", "商业用水户"),
+                userRow(4L, "PUBLIC", "行政事业用水户")
+        ));
+
+        GisFeatureCollectionDTO result = gisService.getFeatures(Set.of("user"));
+
+        assertEquals(4, result.getFeatures().size());
+        assertEquals(Set.of("RESIDENT", "INDUSTRIAL", "COMMERCIAL", "PUBLIC"),
+                result.getFeatures().stream()
+                        .map(feature -> (String) feature.getProperties().get("code"))
+                        .collect(Collectors.toSet()));
+        result.getFeatures().forEach(feature -> {
+            assertEquals("user", feature.getProperties().get("facilityType"));
+            assertEquals("用水户", feature.getProperties().get("facilityTypeName"));
+        });
+    }
+
+    @Test
+    void mapperOverviewKeepsUserCodeAndLabelsAllWaterUsersWithoutCategoryFilter() throws Exception {
+        String gisOverviewSql = mappedSql(
+                "mapper/WaterSupply/WaterSupplyGisMap/WaterSupplyGisMapMapper.xml",
+                WaterSupplyGisMapMapper.class,
+                "selectOverview",
+                null
+        );
+        String gisUsersSql = mappedSql(
+                "mapper/WaterSupply/WaterSupplyGisMap/WaterSupplyGisMapMapper.xml",
+                WaterSupplyGisMapMapper.class,
+                "selectUserFeatures",
+                null
+        );
+        String statisticsOverviewSql = mappedSql(
+                "mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml",
+                PipeNetworkStatisticsMapper.class,
+                "selectFacilityOverview",
+                Collections.singletonMap("status", null)
+        );
+
+        assertTrue(gisOverviewSql.contains("SELECT 'user', '用水户'"));
+        assertTrue(statisticsOverviewSql.contains("SELECT 'user', '用水户'"));
+        assertFalse(gisOverviewSql.contains("大用水户"));
+        assertFalse(statisticsOverviewSql.contains("大用水户"));
+        assertTrue(gisUsersSql.contains("FROM app_user.water_user_info"));
+        assertFalse(gisUsersSql.matches("(?is).*\\buser_type\\s*=.*"),
+                "the user GIS layer must not restrict resident, industrial, commercial, or public-service users");
+        assertFalse(statisticsOverviewSql.matches("(?is).*\\buser_type\\s*=.*"),
+                "facility statistics must include every water user category");
+    }
+
+    @Test
+    void statisticsExportCreatesUnifiedWaterUserWorksheet() throws Exception {
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+        new PipeNetworkStatisticsExportServiceImpl().write(output, new PipeNetworkStatisticsDashboardDTO());
+
+        try (Workbook workbook = new XSSFWorkbook(new ByteArrayInputStream(output.toByteArray()))) {
+            assertNotNull(workbook.getSheet("用水户统计"));
+            assertNull(workbook.getSheet("大用水户统计"));
+        }
+    }
+
+    private Map<String, Object> userRow(Long id, String code, String name) {
+        return Map.of(
+                "id", id,
+                "code", code,
+                "name", name,
+                "status", "0",
+                "location", "测试地址",
+                "longitude", new BigDecimal("113.12345678"),
+                "latitude", new BigDecimal("23.12345678")
+        );
+    }
+
+    private String mappedSql(String resource, Class<?> mapperType, String statementId, Object parameter) throws Exception {
+        Configuration configuration = new Configuration();
+        configuration.addMapper(mapperType);
+        try (InputStream input = Resources.getResourceAsStream(resource)) {
+            new XMLMapperBuilder(input, configuration, resource, configuration.getSqlFragments()).parse();
+        }
+        MappedStatement statement = configuration.getMappedStatement(mapperType.getName() + "." + statementId);
+        return statement.getBoundSql(parameter).getSql().replaceAll("\\s+", " ").trim();
+    }
+}