浏览代码

feat(drainage): 排水基础数据表重建与接口改造

排水管网
- PipeNetworkBase 增加类型常量(0燃气/1排水/2供水),燃气、排水查询统一引用常量
- PipeNetworkPageInDTO 扩展编码/位置/建设日期区间/管径区间等筛选条件
- 新增 DrainagePipeNetworkController(/api/drainage/pipeNetworkBase/{page,map,filterOptions})
- PipeNetworkBaseService 增加排水专用方法,分页与地图共用条件构造器,强制 network_type=1
- PipeNetworkInfoController 裁剪为仅保留 /page,删除无调用的增删改、批量删除、设备绑定端点

工程设施
- EngineeringFacility 改为 drainage_engineering_facility 口径:主键 facilityId,
  点要素坐标,新增编码/等级/管理单位/建设日期/设计流量扬程调蓄容积/逻辑删除
- 新增 EngineeringFacilityPageInDTO,Service 增加地图查询与筛选下拉
- Controller 增加 /map、/filterOptions,写接口同步新字段

易积水点
- WaterloggingPoint 改为 drainage_waterlogging_point 口径:主键 pointId,
  删除 time/waterlogging_count/waterlogging_points,equipment_id 改为 camera_ids
- 新增 WaterloggingPointPageInDTO,Service 增加地图查询、筛选下拉、摄像头关联
  (bindCameras 整体替换 + 跨点位占用校验)
- Controller 增加 /map、/filterOptions、POST /{id}/cameras,删除 /bindEquipment
- DrainageVideoMapper / DrainageVideoService 同步切到新表与 camera_ids

其他
- DrainageEquipmentBindingServiceImpl:易积水点改为读 camera_ids,写入分支返回明确提示
- 两处 cockpit 适配器同步字段变更;3 个单测的 setter 与断言更新
- 新增 SQL:工程设施建表迁移、易积水点建表迁移、积水等级字典、基础数据菜单与按钮权限
null 11 小时之前
父节点
当前提交
d9d6e4fabd
共有 26 个文件被更改,包括 810 次插入 和 376 次删除
  1. 62 0
      pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/DrainagePipeNetworkController.java
  2. 31 13
      pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/EngineeringFacilityController.java
  3. 13 110
      pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/PipeNetworkInfoController.java
  4. 38 18
      pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/WaterloggingPointController.java
  5. 4 4
      pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit/BusinessCockpitInfrastructureBaseArchivesAdapterTest.java
  6. 4 5
      pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit/BusinessCockpitInfrastructureOperatingInformationAdapterTest.java
  7. 5 5
      pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit/CockpitFacilityCountCrossEndpointContractTest.java
  8. 11 0
      pipe-network-service/zksy-system/src/main/java/com/zksy/base/domain/PipeNetworkBase.java
  9. 20 1
      pipe-network-service/zksy-system/src/main/java/com/zksy/base/dto/PipeNetworkPageInDTO.java
  10. 25 0
      pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/PipeNetworkBaseService.java
  11. 112 0
      pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/impl/PipeNetworkBaseServiceImpl.java
  12. 6 5
      pipe-network-service/zksy-system/src/main/java/com/zksy/cockpit/infrastructure/BusinessCockpitInfrastructureBaseArchivesAdapter.java
  13. 9 7
      pipe-network-service/zksy-system/src/main/java/com/zksy/cockpit/infrastructure/BusinessCockpitInfrastructureOperatingInformationAdapter.java
  14. 64 16
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/domain/EngineeringFacility.java
  15. 64 21
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/domain/WaterloggingPoint.java
  16. 43 0
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/dto/EngineeringFacilityPageInDTO.java
  17. 37 0
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/dto/WaterloggingPointPageInDTO.java
  18. 8 7
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/mapper/DrainageVideoMapper.java
  19. 5 5
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/DrainageVideoService.java
  20. 13 2
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/EngineeringFacilityService.java
  21. 3 27
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/PipeNetworkInfoService.java
  22. 15 3
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/WaterloggingPointService.java
  23. 12 10
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/DrainageEquipmentBindingServiceImpl.java
  24. 64 14
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/EngineeringFacilityServiceImpl.java
  25. 3 67
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/PipeNetworkInfoServiceImpl.java
  26. 139 36
      pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/WaterloggingPointServiceImpl.java

+ 62 - 0
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/DrainagePipeNetworkController.java

@@ -0,0 +1,62 @@
+package com.zksy.web.controller.drainage;
+
+import com.zksy.base.domain.PipeNetworkBase;
+import com.zksy.base.dto.PipeNetworkPageInDTO;
+import com.zksy.base.service.PipeNetworkBaseService;
+import com.zksy.common.annotation.Anonymous;
+import com.zksy.common.core.domain.AjaxResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 排水管网基础数据管理
+ * <p>数据源统一为 pipe_network_base,且强制 network_type=1(排水设施)。</p>
+ * <p>排水管网数据由外部导入维护,本模块只提供查询能力:分页列表、地图数据、详情。</p>
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/drainage/pipeNetworkBase")
+@Api(tags = "排水管网基础数据管理")
+public class DrainagePipeNetworkController {
+
+    @Autowired
+    private PipeNetworkBaseService pipeNetworkBaseService;
+
+    @Anonymous
+    @GetMapping("/page")
+    @ApiOperation(value = "排水管网分页查询")
+    public AjaxResult page(PipeNetworkPageInDTO dto) {
+        return AjaxResult.success(pipeNetworkBaseService.queryDrainageByPage(dto));
+    }
+
+    @Anonymous
+    @GetMapping("/map")
+    @ApiOperation(value = "排水管网地图数据(不分页,按筛选条件返回带坐标的记录)")
+    public AjaxResult map(PipeNetworkPageInDTO dto) {
+        return AjaxResult.success(pipeNetworkBaseService.listDrainageForMap(dto));
+    }
+
+    @Anonymous
+    @GetMapping("/filterOptions")
+    @ApiOperation(value = "排水管网筛选下拉项(材质、管养单位)")
+    public AjaxResult filterOptions() {
+        return AjaxResult.success(pipeNetworkBaseService.getDrainageFilterOptions());
+    }
+
+    @Anonymous
+    @GetMapping("/{id}")
+    @ApiOperation(value = "排水管网详情")
+    public AjaxResult getById(@PathVariable String id) {
+        PipeNetworkBase entity = pipeNetworkBaseService.getDrainageById(id);
+        if (entity == null) {
+            return AjaxResult.error("该排水管网不存在");
+        }
+        return AjaxResult.success(entity);
+    }
+}

+ 31 - 13
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/EngineeringFacilityController.java

@@ -6,20 +6,29 @@ import com.zksy.common.annotation.Log;
 import com.zksy.common.core.domain.AjaxResult;
 import com.zksy.common.enums.BusinessType;
 import com.zksy.drainage.domain.EngineeringFacility;
+import com.zksy.drainage.dto.EngineeringFacilityPageInDTO;
 import com.zksy.drainage.service.EngineeringFacilityService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
 import java.util.Map;
 
 /**
- * 工程设施基础数据管理
+ * 工程设施基础数据管理(闸门 / 调蓄设施 / 泵站)
+ * <p>页面侧为只读:查询、筛选、详情与 GIS 叠加展示;
+ * 写接口保留供数据导入/后台维护,字段口径与 drainage_engineering_facility 一致。</p>
  */
 @Slf4j
 @RestController
@@ -33,13 +42,22 @@ public class EngineeringFacilityController {
     @Anonymous
     @GetMapping("/page")
     @ApiOperation(value = "工程设施分页查询")
-    public Page<EngineeringFacility> page(
-            @ApiParam("页码") @RequestParam(defaultValue = "1") long pageNum,
-            @ApiParam("每页数量") @RequestParam(defaultValue = "10") long pageSize,
-            @ApiParam("设施名称") @RequestParam(required = false) String name,
-            @ApiParam("行政区域") @RequestParam(required = false) String area,
-            @ApiParam("设施类型") @RequestParam(required = false) String facilityType) {
-        return service.findByPage(pageNum, pageSize, name, area, facilityType);
+    public Page<EngineeringFacility> page(EngineeringFacilityPageInDTO dto) {
+        return service.findByPage(dto);
+    }
+
+    @Anonymous
+    @GetMapping("/map")
+    @ApiOperation(value = "工程设施地图数据(不分页,仅返回带坐标的记录)")
+    public AjaxResult map(EngineeringFacilityPageInDTO dto) {
+        return AjaxResult.success(service.listForMap(dto));
+    }
+
+    @Anonymous
+    @GetMapping("/filterOptions")
+    @ApiOperation(value = "工程设施筛选下拉项")
+    public AjaxResult filterOptions() {
+        return AjaxResult.success(service.getFilterOptions());
     }
 
     @Anonymous
@@ -104,13 +122,13 @@ public class EngineeringFacilityController {
     @PostMapping("/bindEquipment")
     @ApiOperation(value = "绑定设备到工程设施")
     public AjaxResult bindEquipment(@RequestBody Map<String, Object> params) {
-        String partitionId = (String) params.get("partitionId");
+        String facilityId = (String) params.get("partitionId");
         @SuppressWarnings("unchecked")
         List<String> equipmentIds = (List<String>) params.get("equipmentIds");
-        if (partitionId == null || equipmentIds == null || equipmentIds.isEmpty()) {
+        if (facilityId == null || equipmentIds == null || equipmentIds.isEmpty()) {
             return AjaxResult.error("参数不完整");
         }
-        boolean success = service.bindEquipment(partitionId, equipmentIds);
+        boolean success = service.bindEquipment(facilityId, equipmentIds);
         return success ? AjaxResult.success() : AjaxResult.error("绑定失败");
     }
 

+ 13 - 110
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/PipeNetworkInfoController.java

@@ -2,9 +2,6 @@ package com.zksy.web.controller.drainage;
 
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.zksy.common.annotation.Anonymous;
-import com.zksy.common.annotation.Log;
-import com.zksy.common.core.domain.AjaxResult;
-import com.zksy.common.enums.BusinessType;
 import com.zksy.drainage.domain.PipeNetworkInfo;
 import com.zksy.drainage.service.PipeNetworkInfoService;
 import io.swagger.annotations.Api;
@@ -12,19 +9,25 @@ import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
-
-import java.util.List;
-import java.util.Map;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
 
 /**
- * 排水管网基础数据管理
+ * 排水管网基础数据查询(旧表 psgw_pipe_network_info)
+ * <p>
+ * 仅保留分页查询:综合风险区域分析、综合风险统计分析、管网运行情况三个页面
+ * 仍依赖本表的 equipment_id(关联设备)与 points(多节点坐标),
+ * 这两项在 pipe_network_base 中不存在,故暂不能迁到新接口。
+ * <p>
+ * 新增 / 修改 / 删除 / 批量删除 / 列表 / 详情 / 设备绑定等端点已无调用方,已于本次清理移除。
+ * 新页面请改用 {@link DrainagePipeNetworkController}(/api/drainage/pipeNetworkBase,数据源 pipe_network_base)。
  */
 @Slf4j
 @RestController
 @RequestMapping("/api/drainage/pipeNetwork")
-@Api(tags = "排水管网基础数据管理")
+@Api(tags = "排水管网基础数据查询(旧表,仅保留分页)")
 public class PipeNetworkInfoController {
 
     @Autowired
@@ -41,104 +44,4 @@ public class PipeNetworkInfoController {
             @ApiParam("管网类型") @RequestParam(required = false) String networkType) {
         return service.findByPage(pageNum, pageSize, name, area, networkType);
     }
-
-    /**
-     * 查询所有已被关联的设备ID列表
-     * 返回 Map: { equipmentId -> 关联的管网名称 }
-     * 可选excludeId参数排除某个管网自己的关联
-     */
-    @Anonymous
-    @GetMapping("/boundEquipmentIds")
-    @ApiOperation(value = "查询所有已关联的设备ID")
-    public AjaxResult boundEquipmentIds(
-            @ApiParam("排除的管网ID") @RequestParam(required = false) String excludeId) {
-        List<PipeNetworkInfo> all = service.list();
-        Map<String, String> boundMap = new java.util.HashMap<>();
-        for (PipeNetworkInfo p : all) {
-            if (p.getEquipmentId() != null && !p.getEquipmentId().isEmpty()) {
-                // 排除当前管网自己的关联
-                if (excludeId != null && p.getId().equals(excludeId)) continue;
-                String[] ids = p.getEquipmentId().split(",");
-                for (String id : ids) {
-                    String trimId = id.trim();
-                    if (!trimId.isEmpty()) {
-                        boundMap.put(trimId, p.getName() != null ? p.getName() : "");
-                    }
-                }
-            }
-        }
-        return AjaxResult.success(boundMap);
-    }
-
-    @Anonymous
-    @GetMapping("/{id}")
-    @ApiOperation(value = "查询排水管网详情")
-    public AjaxResult getById(@PathVariable String id) {
-        PipeNetworkInfo entity = service.getById(id);
-        if (entity == null) {
-            return AjaxResult.error("该排水管网不存在");
-        }
-        return AjaxResult.success(entity);
-    }
-
-    @Anonymous
-    @GetMapping("/list")
-    @ApiOperation(value = "查询所有排水管网")
-    public AjaxResult list() {
-        return AjaxResult.success(service.list());
-    }
-
-    @Anonymous
-    @PostMapping
-    @ApiOperation(value = "新增排水管网")
-    @Log(title = "新增排水管网", businessType = BusinessType.INSERT)
-    @Transactional
-    public AjaxResult save(@RequestBody PipeNetworkInfo entity) {
-        boolean saved = service.saveEntity(entity);
-        return saved ? AjaxResult.success("新增成功") : AjaxResult.error("新增失败");
-    }
-
-    @Anonymous
-    @PutMapping
-    @ApiOperation(value = "修改排水管网")
-    @Log(title = "修改排水管网", businessType = BusinessType.UPDATE)
-    @Transactional
-    public AjaxResult update(@RequestBody PipeNetworkInfo entity) {
-        boolean updated = service.updateEntity(entity);
-        return updated ? AjaxResult.success("修改成功") : AjaxResult.error("修改失败");
-    }
-
-    @Anonymous
-    @DeleteMapping("/{id}")
-    @ApiOperation(value = "删除排水管网")
-    @Log(title = "删除排水管网", businessType = BusinessType.DELETE)
-    @Transactional
-    public AjaxResult deleteById(@PathVariable String id) {
-        boolean deleted = service.removeEntity(id);
-        return deleted ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
-    }
-
-    @Anonymous
-    @DeleteMapping("/batch")
-    @ApiOperation(value = "批量删除排水管网")
-    @Log(title = "批量删除排水管网", businessType = BusinessType.DELETE)
-    @Transactional
-    public AjaxResult deleteBatch(@RequestBody List<String> ids) {
-        boolean deleted = service.removeBatchEntity(ids);
-        return deleted ? AjaxResult.success("批量删除成功") : AjaxResult.error("批量删除失败");
-    }
-
-    @Anonymous
-    @PostMapping("/bindEquipment")
-    @ApiOperation(value = "绑定设备到排水管网")
-    public AjaxResult bindEquipment(@RequestBody Map<String, Object> params) {
-        String partitionId = (String) params.get("partitionId");
-        @SuppressWarnings("unchecked")
-        List<String> equipmentIds = (List<String>) params.get("equipmentIds");
-        if (partitionId == null || equipmentIds == null || equipmentIds.isEmpty()) {
-            return AjaxResult.error("参数不完整");
-        }
-        boolean success = service.bindEquipment(partitionId, equipmentIds);
-        return success ? AjaxResult.success() : AjaxResult.error("绑定失败");
-    }
 }

+ 38 - 18
pipe-network-service/zksy-admin/src/main/java/com/zksy/web/controller/drainage/WaterloggingPointController.java

@@ -6,20 +6,29 @@ import com.zksy.common.annotation.Log;
 import com.zksy.common.core.domain.AjaxResult;
 import com.zksy.common.enums.BusinessType;
 import com.zksy.drainage.domain.WaterloggingPoint;
+import com.zksy.drainage.dto.WaterloggingPointPageInDTO;
 import com.zksy.drainage.service.WaterloggingPointService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
 /**
  * 易积水点管理
+ * <p>易积水点关联的是视频摄像头,不是通用监测设备;前端在地图/列表中点击可直接播放关联摄像头。</p>
  */
 @Slf4j
 @RestController
@@ -33,12 +42,22 @@ public class WaterloggingPointController {
     @Anonymous
     @GetMapping("/page")
     @ApiOperation(value = "易积水点分页查询")
-    public Page<WaterloggingPoint> page(
-            @ApiParam("页码") @RequestParam(defaultValue = "1") long pageNum,
-            @ApiParam("每页数量") @RequestParam(defaultValue = "10") long pageSize,
-            @ApiParam("监测点名称") @RequestParam(required = false) String name,
-            @ApiParam("行政区域") @RequestParam(required = false) String area) {
-        return service.findByPage(pageNum, pageSize, name, area);
+    public Page<WaterloggingPoint> page(WaterloggingPointPageInDTO dto) {
+        return service.findByPage(dto);
+    }
+
+    @Anonymous
+    @GetMapping("/map")
+    @ApiOperation(value = "易积水点地图数据(不分页,仅返回带坐标的记录)")
+    public AjaxResult map(WaterloggingPointPageInDTO dto) {
+        return AjaxResult.success(service.listForMap(dto));
+    }
+
+    @Anonymous
+    @GetMapping("/filterOptions")
+    @ApiOperation(value = "易积水点筛选下拉项")
+    public AjaxResult filterOptions() {
+        return AjaxResult.success(service.getFilterOptions());
     }
 
     @Anonymous
@@ -100,16 +119,17 @@ public class WaterloggingPointController {
     }
 
     @Anonymous
-    @PostMapping("/bindEquipment")
-    @ApiOperation(value = "绑定设备到易积水点")
-    public AjaxResult bindEquipment(@RequestBody Map<String, Object> params) {
-        String partitionId = (String) params.get("partitionId");
-        @SuppressWarnings("unchecked")
-        List<String> equipmentIds = (List<String>) params.get("equipmentIds");
-        if (partitionId == null || equipmentIds == null || equipmentIds.isEmpty()) {
-            return AjaxResult.error("参数不完整");
+    @PostMapping("/{id}/cameras")
+    @ApiOperation(value = "关联摄像头到易积水点(整体替换,空列表表示解除全部)")
+    public AjaxResult bindCameras(@PathVariable String id, @RequestBody Map<String, Object> params) {
+        Object raw = params == null ? null : params.get("cameraIds");
+        List<String> cameraIds = new ArrayList<>();
+        if (raw instanceof List) {
+            for (Object item : (List<?>) raw) {
+                if (item != null) cameraIds.add(String.valueOf(item));
+            }
         }
-        boolean success = service.bindEquipment(partitionId, equipmentIds);
-        return success ? AjaxResult.success() : AjaxResult.error("绑定失败");
+        boolean success = service.bindCameras(id, cameraIds);
+        return success ? AjaxResult.success("关联成功") : AjaxResult.error("关联失败");
     }
 }

+ 4 - 4
pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit/BusinessCockpitInfrastructureBaseArchivesAdapterTest.java

@@ -70,10 +70,10 @@ class BusinessCockpitInfrastructureBaseArchivesAdapterTest {
         pipe.setBuildDate(java.sql.Date.valueOf(LocalDate.of(2010, 3, 4)));
 
         EngineeringFacility drainage = new EngineeringFacility();
-        drainage.setId("DRAIN-001");
-        drainage.setName("一号调蓄池");
-        drainage.setArea("CB");
-        drainage.setFacilityType("调蓄设施");
+        drainage.setFacilityId("DRAIN-001");
+        drainage.setFacilityName("一号调蓄池");
+        drainage.setLocation("CB");
+        drainage.setFacilityType("1");
 
         when(plantService.list()).thenReturn(Collections.singletonList(plant));
         when(pumpStationService.list()).thenReturn(Collections.singletonList(pump));

+ 4 - 5
pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit/BusinessCockpitInfrastructureOperatingInformationAdapterTest.java

@@ -73,10 +73,9 @@ class BusinessCockpitInfrastructureOperatingInformationAdapterTest {
         pipe.setUpdateTime(LocalDateTime.parse("2026-09-02T09:57:00"));
 
         EngineeringFacility facility = new EngineeringFacility();
-        facility.setId("DRAIN-001");
-        facility.setName("一号调蓄池");
-        facility.setFacilityType("调蓄设施");
-        facility.setPointCount(3);
+        facility.setFacilityId("DRAIN-001");
+        facility.setFacilityName("一号调蓄池");
+        facility.setFacilityType("1");
         facility.setUpdateTime(LocalDateTime.parse("2026-09-02T09:56:00"));
 
         when(plantService.list()).thenReturn(Collections.singletonList(plant));
@@ -113,7 +112,7 @@ class BusinessCockpitInfrastructureOperatingInformationAdapterTest {
                         .findFirst()
                         .orElseThrow(AssertionError::new);
         assertEquals("DRAINAGE", drainageMetric.getIndustry());
-        assertEquals(new BigDecimal("3"), drainageMetric.getValue());
+        assertEquals(BigDecimal.ONE, drainageMetric.getValue());
     }
 
     @Test

+ 5 - 5
pipe-network-service/zksy-admin/src/test/java/com/zksy/web/controller/cockpit/CockpitFacilityCountCrossEndpointContractTest.java

@@ -56,13 +56,13 @@ class CockpitFacilityCountCrossEndpointContractTest {
         ManholeBase manhole = new ManholeBase();
         manhole.setManholeCode("MH-1");
         EngineeringFacility gate = new EngineeringFacility();
-        gate.setId("GATE-1");
-        gate.setFacilityType("闸门");
+        gate.setFacilityId("GATE-1");
+        gate.setFacilityType("0");
         EngineeringFacility pump = new EngineeringFacility();
-        pump.setId("ENGINEERING-PUMP");
-        pump.setFacilityType("泵站");
+        pump.setFacilityId("ENGINEERING-PUMP");
+        pump.setFacilityType("2");
         EngineeringFacility unknown = new EngineeringFacility();
-        unknown.setId("UNKNOWN-1");
+        unknown.setFacilityId("UNKNOWN-1");
         unknown.setFacilityType("unclassified");
         WaterPlantInfo missingCode = new WaterPlantInfo();
         when(plants.list()).thenReturn(Arrays.asList(plant, missingCode));

+ 11 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/domain/PipeNetworkBase.java

@@ -29,6 +29,17 @@ public class PipeNetworkBase {
      */
     public static final String NETWORK_TYPE_GAS = "0";
 
+    /**
+     * 设施类型:排水设施(network_type = 1)
+     * <p>排水模块所有查询 pipe_network_base 的接口都必须带上该条件</p>
+     */
+    public static final String NETWORK_TYPE_DRAINAGE = "1";
+
+    /**
+     * 设施类型:供水设施(network_type = 2)
+     */
+    public static final String NETWORK_TYPE_WATER = "2";
+
     @TableId(value = "network_id", type = IdType.ASSIGN_UUID)
     @ApiModelProperty("管网设施ID")
     private String networkId;

+ 20 - 1
pipe-network-service/zksy-system/src/main/java/com/zksy/base/dto/PipeNetworkPageInDTO.java

@@ -5,12 +5,16 @@ import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 @Data
 @ApiModel(value = "管网分页查询入参", description = "管网分页查询入参")
 public class PipeNetworkPageInDTO implements Serializable {
     private static final long serialVersionUID = 1L;
 
+    @ApiModelProperty(value = "设施编码")
+    private String networkCode;
+
     @ApiModelProperty(value = "管网名称")
     private String networkName;
 
@@ -26,7 +30,22 @@ public class PipeNetworkPageInDTO implements Serializable {
     @ApiModelProperty(value = "状态")
     private String status;
 
-    @ApiModelProperty(value = "当前记录起始索引", required = true)
+    @ApiModelProperty(value = "位置描述(模糊匹配)")
+    private String location;
+
+    @ApiModelProperty(value = "建设日期起(yyyy-MM-dd,含)")
+    private String buildDateStart;
+
+    @ApiModelProperty(value = "建设日期止(yyyy-MM-dd,含)")
+    private String buildDateEnd;
+
+    @ApiModelProperty(value = "管径下限(毫米,含)")
+    private BigDecimal diameterMin;
+
+    @ApiModelProperty(value = "管径上限(毫米,含)")
+    private BigDecimal diameterMax;
+
+    @ApiModelProperty(value = "当前页码", required = true)
     private Long pageNum;
 
     @ApiModelProperty(value = "每页显示记录数", required = true)

+ 25 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/PipeNetworkBaseService.java

@@ -7,6 +7,7 @@ import com.zksy.base.dto.PipeNetworkExportDTO;
 import com.zksy.base.dto.PipeNetworkPageInDTO;
 
 import java.util.List;
+import java.util.Map;
 
 public interface PipeNetworkBaseService extends IService<PipeNetworkBase> {
 
@@ -41,6 +42,30 @@ public interface PipeNetworkBaseService extends IService<PipeNetworkBase> {
      */
     List<PipeNetworkExportDTO> exportGasData(String networkName, String status);
 
+    /* ==================== 排水模块专用查询(强制 network_type=1) ==================== */
+
+    /**
+     * 排水设施分页查询(支持编码/名称/等级/管养单位/材质/状态/位置/建设日期区间/管径区间)
+     * <p>仅查询 network_type=1 的排水设施</p>
+     */
+    Page<PipeNetworkBase> queryDrainageByPage(PipeNetworkPageInDTO dto);
+
+    /**
+     * 按ID查询排水设施
+     * <p>仅查询 network_type=1 的排水设施,非排水设施返回 null</p>
+     */
+    PipeNetworkBase getDrainageById(String networkId);
+
+    /**
+     * 排水设施地图数据(不分页,仅返回起终点至少一端有坐标的记录)
+     * <p>筛选条件与分页查询一致,用于按筛选结果绘制管网</p>
+     */
+    List<PipeNetworkBase> listDrainageForMap(PipeNetworkPageInDTO dto);
+
+    /**
+     * 排水设施筛选下拉项(材质、管养单位去重值)
+     */
+    Map<String, List<String>> getDrainageFilterOptions();
     boolean saveWithCheck(PipeNetworkBase entity);
 
     boolean saveBatchWithCheck(List<PipeNetworkBase> entityList);

+ 112 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/base/service/impl/PipeNetworkBaseServiceImpl.java

@@ -1,6 +1,7 @@
 package com.zksy.base.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -15,8 +16,12 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -215,6 +220,113 @@ public class PipeNetworkBaseServiceImpl extends ServiceImpl<PipeNetworkBaseMappe
         return buildExportList(this.list(wrapper));
     }
 
+    /* ==================== 排水模块专用查询(强制 network_type=1) ==================== */
+
+    @Override
+    public Page<PipeNetworkBase> queryDrainageByPage(PipeNetworkPageInDTO dto) {
+        long pageNum = dto.getPageNum() == null ? 1L : dto.getPageNum();
+        long pageSize = dto.getPageSize() == null ? 10L : dto.getPageSize();
+        return this.page(new Page<>(pageNum, pageSize), buildDrainageWrapper(dto));
+    }
+
+    @Override
+    public PipeNetworkBase getDrainageById(String networkId) {
+        if (networkId == null || networkId.isEmpty()) {
+            return null;
+        }
+        LambdaQueryWrapper<PipeNetworkBase> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(PipeNetworkBase::getNetworkId, networkId);
+        // 排水模块只允许查询排水设施
+        wrapper.eq(PipeNetworkBase::getNetworkType, PipeNetworkBase.NETWORK_TYPE_DRAINAGE);
+        return this.getOne(wrapper, false);
+    }
+
+    @Override
+    public List<PipeNetworkBase> listDrainageForMap(PipeNetworkPageInDTO dto) {
+        LambdaQueryWrapper<PipeNetworkBase> wrapper = buildDrainageWrapper(dto);
+        // 起终点至少一端有坐标才返回,避免前端拿到无法绘制的空几何
+        wrapper.and(w -> w
+                .and(s -> s.isNotNull(PipeNetworkBase::getStartLongitude)
+                        .isNotNull(PipeNetworkBase::getStartLatitude))
+                .or()
+                .and(e -> e.isNotNull(PipeNetworkBase::getEndLongitude)
+                        .isNotNull(PipeNetworkBase::getEndLatitude)));
+        return this.list(wrapper);
+    }
+
+    /**
+     * 排水设施筛选下拉项(材质、管养单位去重值)
+     */
+    @Override
+    public Map<String, List<String>> getDrainageFilterOptions() {
+        Map<String, List<String>> options = new HashMap<>();
+        options.put("materials", distinctDrainageColumn("material"));
+        options.put("managementUnits", distinctDrainageColumn("management_unit"));
+        return options;
+    }
+
+    /**
+     * 取排水设施某列的去重非空值
+     * <p>列名仅由内部常量传入,不接受外部输入</p>
+     */
+    private List<String> distinctDrainageColumn(String column) {
+        QueryWrapper<PipeNetworkBase> wrapper = new QueryWrapper<>();
+        wrapper.select("DISTINCT " + column)
+                .eq("network_type", PipeNetworkBase.NETWORK_TYPE_DRAINAGE)
+                .isNotNull(column)
+                .ne(column, "")
+                .orderByAsc(column);
+        return this.listObjs(wrapper, obj -> obj == null ? null : obj.toString())
+                .stream()
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * 排水设施查询条件(强制 network_type=1,分页与地图共用)
+     */
+    private LambdaQueryWrapper<PipeNetworkBase> buildDrainageWrapper(PipeNetworkPageInDTO dto) {
+        LambdaQueryWrapper<PipeNetworkBase> wrapper = new LambdaQueryWrapper<>();
+        // 排水模块只允许查询排水设施
+        wrapper.eq(PipeNetworkBase::getNetworkType, PipeNetworkBase.NETWORK_TYPE_DRAINAGE);
+        wrapper.like(hasText(dto.getNetworkCode()), PipeNetworkBase::getNetworkCode, dto.getNetworkCode());
+        wrapper.like(hasText(dto.getNetworkName()), PipeNetworkBase::getNetworkName, dto.getNetworkName());
+        wrapper.eq(hasText(dto.getNetworkLevel()), PipeNetworkBase::getNetworkLevel, dto.getNetworkLevel());
+        wrapper.like(hasText(dto.getManagementUnit()), PipeNetworkBase::getManagementUnit, dto.getManagementUnit());
+        wrapper.like(hasText(dto.getMaterial()), PipeNetworkBase::getMaterial, dto.getMaterial());
+        wrapper.eq(hasText(dto.getStatus()), PipeNetworkBase::getStatus, dto.getStatus());
+        wrapper.like(hasText(dto.getLocation()), PipeNetworkBase::getLocation, dto.getLocation());
+
+        Date buildStart = parseDate(dto.getBuildDateStart());
+        Date buildEnd = parseDate(dto.getBuildDateEnd());
+        wrapper.ge(buildStart != null, PipeNetworkBase::getBuildDate, buildStart);
+        wrapper.le(buildEnd != null, PipeNetworkBase::getBuildDate, buildEnd);
+        wrapper.ge(dto.getDiameterMin() != null, PipeNetworkBase::getDiameter, dto.getDiameterMin());
+        wrapper.le(dto.getDiameterMax() != null, PipeNetworkBase::getDiameter, dto.getDiameterMax());
+
+        wrapper.orderByDesc(PipeNetworkBase::getCreateTime);
+        return wrapper;
+    }
+
+    private static boolean hasText(String value) {
+        return value != null && !value.trim().isEmpty();
+    }
+
+    /**
+     * 解析 yyyy-MM-dd,格式非法时返回 null(视为不按该端筛选)
+     */
+    private static Date parseDate(String value) {
+        if (!hasText(value)) {
+            return null;
+        }
+        try {
+            return java.sql.Date.valueOf(value.trim().substring(0, 10));
+        } catch (RuntimeException e) {
+            log.warn("排水管网查询忽略非法日期参数:{}", value);
+            return null;
+        }
+    }
+
     /**
      * 管网设施列表转导出DTO
      */

+ 6 - 5
pipe-network-service/zksy-system/src/main/java/com/zksy/cockpit/infrastructure/BusinessCockpitInfrastructureBaseArchivesAdapter.java

@@ -103,8 +103,8 @@ public class BusinessCockpitInfrastructureBaseArchivesAdapter
             updatedAt = latest(updatedAt, facility.getUpdateTime());
             updatedAt = latest(updatedAt, facility.getCreateTime());
             // 保留现有工程设施年限映射;本票只统一设施范围,不裁定建设日期来源。
-            add(facilities, key("psgw_engineering_facility", facility.getId(), facility.getId()),
-                    facility.getId(), drainageType(facility.getFacilityType()), null, null,
+            add(facilities, key("drainage_engineering_facility", facility.getFacilityId(), facility.getFacilityCode()),
+                    facility.getFacilityId(), drainageType(facility.getFacilityType()), null, null,
                     facility.getCreateTime() == null ? null : facility.getCreateTime().toLocalDate());
         }
         for (WaterSourceInfo source : safeList(sources.list())) {
@@ -142,9 +142,10 @@ public class BusinessCockpitInfrastructureBaseArchivesAdapter
     private static String drainageType(String value) {
         String type = trimToNull(value);
         if (type == null) return UNCLASSIFIED;
-        if (type.contains("闸")) return "DRAINAGE_GATE";
-        if (type.contains("调蓄") || type.contains("蓄水")) return "DRAINAGE_STORAGE";
-        if (type.contains("泵站")) return "DRAINAGE_PUMP_STATION";
+        // 新口径为字典编码(drainage_facility_type:0闸门 1调蓄设施 2泵站),中文值仅作存量兼容
+        if (EngineeringFacility.TYPE_GATE.equals(type) || type.contains("闸")) return "DRAINAGE_GATE";
+        if (EngineeringFacility.TYPE_STORAGE.equals(type) || type.contains("调蓄") || type.contains("蓄水")) return "DRAINAGE_STORAGE";
+        if (EngineeringFacility.TYPE_PUMP.equals(type) || type.contains("泵站")) return "DRAINAGE_PUMP_STATION";
         return UNCLASSIFIED;
     }
 

+ 9 - 7
pipe-network-service/zksy-system/src/main/java/com/zksy/cockpit/infrastructure/BusinessCockpitInfrastructureOperatingInformationAdapter.java

@@ -128,7 +128,7 @@ public class BusinessCockpitInfrastructureOperatingInformationAdapter
         }
 
         for (EngineeringFacility facility : safeList(engineeringFacilityService.list())) {
-            if (facility == null || isBlank(facility.getId()) || facility.getPointCount() == null) {
+            if (facility == null || isBlank(facility.getFacilityId())) {
                 continue;
             }
             String typeCode = drainageFacilityType(facility.getFacilityType());
@@ -137,17 +137,18 @@ public class BusinessCockpitInfrastructureOperatingInformationAdapter
             }
             String sampledAt = format(facility.getUpdateTime());
             latestUpdatedAt = latest(latestUpdatedAt, sampledAt);
+            // 工程设施是点要素,每个设施计 1 个点(旧表 point_count 已随表结构重建移除)
             metrics.add(metric(
                     "drainage_" + typeCode.toLowerCase() + "_point_count",
-                    isBlank(facility.getName()) ? "排水设施点数" : facility.getName() + "点数",
+                    isBlank(facility.getFacilityName()) ? "排水设施点数" : facility.getFacilityName() + "点数",
                     "CAPACITY",
                     "个",
                     "DRAINAGE",
-                    BigDecimal.valueOf(facility.getPointCount()),
+                    BigDecimal.ONE,
                     null,
                     sampledAt,
                     false,
-                    facility.getId()));
+                    facility.getFacilityId()));
         }
 
         return new CockpitInfrastructureOperatingInformationSnapshot(latestUpdatedAt, metrics);
@@ -193,13 +194,14 @@ public class BusinessCockpitInfrastructureOperatingInformationAdapter
         if (normalized == null) {
             return null;
         }
-        if (normalized.contains("闸")) {
+        // 新口径为字典编码(drainage_facility_type:0闸门 1调蓄设施 2泵站),中文值仅作存量兼容
+        if (EngineeringFacility.TYPE_GATE.equals(normalized) || normalized.contains("闸")) {
             return "gate";
         }
-        if (normalized.contains("调蓄") || normalized.contains("蓄水")) {
+        if (EngineeringFacility.TYPE_STORAGE.equals(normalized) || normalized.contains("调蓄") || normalized.contains("蓄水")) {
             return "storage";
         }
-        if (normalized.contains("泵站")) {
+        if (EngineeringFacility.TYPE_PUMP.equals(normalized) || normalized.contains("泵站")) {
             return "pump_station";
         }
         return null;

+ 64 - 16
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/domain/EngineeringFacility.java

@@ -2,6 +2,7 @@ package com.zksy.drainage.domain;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModelProperty;
@@ -9,47 +10,94 @@ import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
+import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.Date;
 
 /**
- * 工程设施基础数据
+ * 工程设施基础数据(闸门 / 调蓄设施 / 泵站)
+ * <p>一个工程设施在地图上是一个点要素,直接落 WGS84 经纬度。</p>
  */
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
-@TableName(value = "psgw_engineering_facility", schema = "app_user")
+@TableName(value = "drainage_engineering_facility", schema = "app_user")
 public class EngineeringFacility {
 
-    @TableId(value = "id", type = IdType.ASSIGN_UUID)
-    @ApiModelProperty("主键ID")
-    private String id;
+    /** 设施类型:闸门(字典 drainage_facility_type) */
+    public static final String TYPE_GATE = "0";
 
-    @ApiModelProperty("监测点名称/设施名称")
-    private String name;
+    /** 设施类型:调蓄设施 */
+    public static final String TYPE_STORAGE = "1";
 
-    @ApiModelProperty("行政区域")
-    private String area;
+    /** 设施类型:泵站 */
+    public static final String TYPE_PUMP = "2";
 
-    @ApiModelProperty("设施类型(闸门/调蓄设施/泵站)")
+    @TableId(value = "facility_id", type = IdType.ASSIGN_UUID)
+    @ApiModelProperty("设施ID")
+    private String facilityId;
+
+    @ApiModelProperty("设施编码")
+    private String facilityCode;
+
+    @ApiModelProperty("设施名称")
+    private String facilityName;
+
+    @ApiModelProperty("设施类型(0闸门 1调蓄设施 2泵站)")
     private String facilityType;
 
-    @ApiModelProperty("数据时间")
-    private String time;
+    @ApiModelProperty("设施等级")
+    private String facilityLevel;
+
+    @ApiModelProperty("管理单位")
+    private String managementUnit;
+
+    @ApiModelProperty("位置描述")
+    private String location;
+
+    @ApiModelProperty("WGS84 经度")
+    private BigDecimal longitude;
+
+    @ApiModelProperty("WGS84 纬度")
+    private BigDecimal latitude;
 
-    @ApiModelProperty("标记数量(自动计算)")
-    private Integer pointCount;
+    @ApiModelProperty("运行状态(0正常 1检修 2停用 3故障)")
+    private String status;
 
-    @ApiModelProperty("坐标数据JSON")
-    private String points;
+    @ApiModelProperty("建设日期")
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date buildDate;
+
+    @ApiModelProperty("设计流量(m³/s)")
+    private BigDecimal designFlow;
+
+    @ApiModelProperty("设计扬程(m)")
+    private BigDecimal designHead;
+
+    @ApiModelProperty("调蓄容积(m³)")
+    private BigDecimal storageCapacity;
 
     @ApiModelProperty("关联设备ID(多个用逗号分隔)")
     private String equipmentId;
 
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @ApiModelProperty("创建人")
+    private String createBy;
+
     @ApiModelProperty("创建时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime createTime;
 
+    @ApiModelProperty("更新人")
+    private String updateBy;
+
     @ApiModelProperty("更新时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime updateTime;
+
+    @TableLogic(value = "0", delval = "2")
+    @ApiModelProperty("删除标志(0正常 2删除)")
+    private String delFlag;
 }

+ 64 - 21
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/domain/WaterloggingPoint.java

@@ -3,6 +3,7 @@ package com.zksy.drainage.domain;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModelProperty;
@@ -14,49 +15,91 @@ import java.math.BigDecimal;
 import java.time.LocalDateTime;
 
 /**
- * 易积水点管理
+ * 易积水点台账
+ * <p>一个易积水点在地图上就是一个位置,直接落 WGS84 经纬度;
+ * 关联的是视频摄像头(equipment_base.equipment_id),不是通用监测设备。</p>
  */
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
-@TableName(value = "psgw_waterlogging_point", schema = "app_user")
+@TableName(value = "drainage_waterlogging_point", schema = "app_user")
 public class WaterloggingPoint {
 
-    @TableId(value = "id", type = IdType.ASSIGN_UUID)
-    @ApiModelProperty("主键ID")
-    private String id;
+    @TableId(value = "point_id", type = IdType.ASSIGN_UUID)
+    @ApiModelProperty("点位ID")
+    private String pointId;
 
-    @ApiModelProperty("监测点名称")
-    private String name;
+    @ApiModelProperty("点位编码")
+    private String pointCode;
 
-    @ApiModelProperty("行政区域")
-    private String area;
+    @ApiModelProperty("点位名称")
+    private String pointName;
 
-    @ApiModelProperty("数据时间")
-    private String time;
+    @ApiModelProperty("所属区域")
+    private String district;
 
-    @ApiModelProperty("易积水点数量(自动计算)")
-    private Integer waterloggingCount;
+    @ApiModelProperty("位置描述")
+    private String location;
 
-    @ApiModelProperty("易积水点标记坐标JSON")
-    private String waterloggingPoints;
+    @ApiModelProperty("WGS84 经度")
+    private BigDecimal longitude;
 
-    @ApiModelProperty("积水量")
-    @TableField("water_volume")
-    private BigDecimal waterVolume;
+    @ApiModelProperty("WGS84 纬度")
+    private BigDecimal latitude;
 
-    @ApiModelProperty("积水程度(0未积水,1轻度积水,2中度积水,3严重积水)")
+    @ApiModelProperty("积水程度(0未积水 1轻度 2中度 3严重)")
     @TableField("waterlogging_level")
     private Integer waterloggingLevel;
 
-    @ApiModelProperty("关联设备ID(多个用逗号分隔)")
-    private String equipmentId;
+    @ApiModelProperty("积水深度(cm)")
+    @TableField("water_depth")
+    private BigDecimal waterDepth;
+
+    @ApiModelProperty("积水量(m³)")
+    @TableField("water_volume")
+    private BigDecimal waterVolume;
+
+    @ApiModelProperty("积水面积(m²)")
+    @TableField("water_area")
+    private BigDecimal waterArea;
+
+    @ApiModelProperty("风险等级(0低 1中 2高)")
+    @TableField("risk_level")
+    private String riskLevel;
+
+    @ApiModelProperty("责任单位")
+    @TableField("duty_unit")
+    private String dutyUnit;
+
+    @ApiModelProperty("责任人")
+    @TableField("duty_person")
+    private String dutyPerson;
+
+    @ApiModelProperty("联系电话")
+    @TableField("duty_phone")
+    private String dutyPhone;
+
+    @ApiModelProperty("关联摄像头ID(多个用逗号分隔)")
+    private String cameraIds;
+
+    @ApiModelProperty("备注")
+    private String remark;
+
+    @ApiModelProperty("创建人")
+    private String createBy;
 
     @ApiModelProperty("创建时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime createTime;
 
+    @ApiModelProperty("更新人")
+    private String updateBy;
+
     @ApiModelProperty("更新时间")
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private LocalDateTime updateTime;
+
+    @TableLogic(value = "0", delval = "2")
+    @ApiModelProperty("删除标志(0正常 2删除)")
+    private String delFlag;
 }

+ 43 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/dto/EngineeringFacilityPageInDTO.java

@@ -0,0 +1,43 @@
+package com.zksy.drainage.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 工程设施查询入参(分页查询与地图查询共用)
+ */
+@Data
+@ApiModel(value = "工程设施查询入参", description = "工程设施查询入参")
+public class EngineeringFacilityPageInDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "设施编码")
+    private String facilityCode;
+
+    @ApiModelProperty(value = "设施名称")
+    private String facilityName;
+
+    @ApiModelProperty(value = "设施类型(0闸门 1调蓄设施 2泵站)")
+    private String facilityType;
+
+    @ApiModelProperty(value = "设施等级")
+    private String facilityLevel;
+
+    @ApiModelProperty(value = "管理单位")
+    private String managementUnit;
+
+    @ApiModelProperty(value = "位置描述")
+    private String location;
+
+    @ApiModelProperty(value = "运行状态(0正常 1检修 2停用 3故障)")
+    private String status;
+
+    @ApiModelProperty(value = "当前记录起始索引")
+    private Long pageNum;
+
+    @ApiModelProperty(value = "每页显示记录数")
+    private Long pageSize;
+}

+ 37 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/dto/WaterloggingPointPageInDTO.java

@@ -0,0 +1,37 @@
+package com.zksy.drainage.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 易积水点查询入参(分页查询与地图查询共用)
+ */
+@Data
+@ApiModel(value = "易积水点查询入参", description = "易积水点查询入参")
+public class WaterloggingPointPageInDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "点位编码")
+    private String pointCode;
+
+    @ApiModelProperty(value = "点位名称")
+    private String pointName;
+
+    @ApiModelProperty(value = "所属区域")
+    private String district;
+
+    @ApiModelProperty(value = "积水程度(0未积水 1轻度 2中度 3严重)")
+    private Integer waterloggingLevel;
+
+    @ApiModelProperty(value = "风险等级(0低 1中 2高)")
+    private String riskLevel;
+
+    @ApiModelProperty(value = "当前记录起始索引")
+    private Long pageNum;
+
+    @ApiModelProperty(value = "每页显示记录数")
+    private Long pageSize;
+}

+ 8 - 7
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/mapper/DrainageVideoMapper.java

@@ -10,16 +10,16 @@ import org.apache.ibatis.annotations.*;
 public interface DrainageVideoMapper {
     String VIEW = "SELECT e.equipment_id AS video_id,e.equipment_code AS device_code,e.equipment_name AS device_name," +
         "e.district,e.equipment_location AS location,e.longitude,e.latitude,v.source_type," +
-        "w.id AS point_id,w.name AS point_name,(f.user_id IS NOT NULL) AS favorite " +
+        "w.point_id AS point_id,w.point_name AS point_name,(f.user_id IS NOT NULL) AS favorite " +
         "FROM app_user.equipment_base e JOIN app_user.equipment_video_binding v ON v.equipment_id=e.equipment_id " +
-        "LEFT JOIN app_user.psgw_waterlogging_point w ON STRPOS(CONCAT(',',REPLACE(COALESCE(w.equipment_id,''),' ',''),','),CONCAT(',',e.equipment_id,','))>0 " +
+        "LEFT JOIN app_user.drainage_waterlogging_point w ON STRPOS(CONCAT(',',REPLACE(COALESCE(w.camera_ids,''),' ',''),','),CONCAT(',',e.equipment_id,','))>0 " +
         "LEFT JOIN app_user.drainage_video_favorite f ON f.equipment_id=e.equipment_id AND f.user_id=#{userId} ";
     String FILTER = "WHERE e.equipment_type_id=20 AND e.del_flag='0' " +
         "<if test='query != null and query != &quot;&quot;'>AND (e.equipment_name LIKE CONCAT('%',#{query},'%') OR e.equipment_code LIKE CONCAT('%',#{query},'%'))</if> " +
         "<if test='district != null'>AND e.district=#{district}</if> " +
-        "<if test='pointId != null and pointId != &quot;&quot;'>AND w.id=#{pointId}</if> " +
-        "<if test='unbound == true'>AND w.id IS NULL</if> " +
-        "<if test='unbound == false'>AND w.id IS NOT NULL</if> " +
+        "<if test='pointId != null and pointId != &quot;&quot;'>AND w.point_id=#{pointId}</if> " +
+        "<if test='unbound == true'>AND w.point_id IS NULL</if> " +
+        "<if test='unbound == false'>AND w.point_id IS NOT NULL</if> " +
         "<if test='favoriteOnly == true'>AND f.user_id IS NOT NULL</if> " +
         "<if test='sourceType != null and sourceType != &quot;&quot;'>AND v.source_type=#{sourceType}</if> " +
         "ORDER BY e.create_time DESC,e.equipment_id";
@@ -32,7 +32,8 @@ public interface DrainageVideoMapper {
     @Select(VIEW + "WHERE e.equipment_type_id=20 AND e.del_flag='0' ORDER BY e.district,e.equipment_id")
     List<DrainageVideoResource> all(@Param("userId") Long userId);
 
-    @Select("SELECT id,name,area FROM app_user.psgw_waterlogging_point ORDER BY name,id")
+    // 别名保持 id/name/area,兼容视频分组页面既有的消费方
+    @Select("SELECT point_id AS id,point_name AS name,district AS area FROM app_user.drainage_waterlogging_point WHERE del_flag='0' ORDER BY point_name,point_id")
     List<Map<String,Object>> points();
 
     @Insert("INSERT INTO app_user.drainage_video_favorite(user_id,equipment_id) VALUES(#{userId},#{videoId}) ON CONFLICT(user_id,equipment_id) DO NOTHING")
@@ -41,6 +42,6 @@ public interface DrainageVideoMapper {
     @Delete("DELETE FROM app_user.drainage_video_favorite WHERE user_id=#{userId} AND equipment_id=#{videoId}")
     int unfavorite(@Param("userId") Long userId,@Param("videoId") String videoId);
 
-    @Update("UPDATE app_user.psgw_waterlogging_point SET equipment_id=#{equipmentIds},update_time=CURRENT_TIMESTAMP WHERE id=#{pointId}")
+    @Update("UPDATE app_user.drainage_waterlogging_point SET camera_ids=#{equipmentIds},update_time=CURRENT_TIMESTAMP WHERE point_id=#{pointId}")
     int updatePoint(@Param("pointId") String pointId,@Param("equipmentIds") String equipmentIds);
 }

+ 5 - 5
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/DrainageVideoService.java

@@ -73,19 +73,19 @@ public class DrainageVideoService {
         List<WaterloggingPoint> all=points.selectList(null);
         WaterloggingPoint target=null;
         if(pointId!=null&&!pointId.isBlank()) {
-            target=all.stream().filter(p->pointId.equals(p.getId())).findFirst().orElseThrow(()->new ServiceException("易积水点不存在"));
+            target=all.stream().filter(p->pointId.equals(p.getPointId())).findFirst().orElseThrow(()->new ServiceException("易积水点不存在"));
             for(WaterloggingPoint point:all) {
-                if(!pointId.equals(point.getId())&&ids(point.getEquipmentId()).contains(videoId))
+                if(!pointId.equals(point.getPointId())&&ids(point.getCameraIds()).contains(videoId))
                     throw new ServiceException("视频已关联其他易积水点,请先解除关联");
             }
             Map<String,String> occupied=binding.findBoundEquipment(DrainageEquipmentBindingService.TYPE_WATERLOGGING,pointId);
             if(occupied.containsKey(videoId))throw new ServiceException("视频已被其他位置关联:"+occupied.get(videoId));
-            Set<String> merged=ids(target.getEquipmentId());merged.add(videoId);
+            Set<String> merged=ids(target.getCameraIds());merged.add(videoId);
             videos.updatePoint(pointId,String.join(",",merged));
         } else {
             for(WaterloggingPoint point:all) {
-                Set<String> existing=ids(point.getEquipmentId());
-                if(existing.remove(videoId))videos.updatePoint(point.getId(),String.join(",",existing));
+                Set<String> existing=ids(point.getCameraIds());
+                if(existing.remove(videoId))videos.updatePoint(point.getPointId(),String.join(",",existing));
             }
         }
     }

+ 13 - 2
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/EngineeringFacilityService.java

@@ -3,8 +3,10 @@ package com.zksy.drainage.service;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.zksy.drainage.domain.EngineeringFacility;
+import com.zksy.drainage.dto.EngineeringFacilityPageInDTO;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 工程设施基础数据 Service接口
@@ -14,8 +16,17 @@ public interface EngineeringFacilityService extends IService<EngineeringFacility
     /**
      * 分页查询
      */
-    Page<EngineeringFacility> findByPage(long pageNum, long pageSize,
-                                         String name, String area, String facilityType);
+    Page<EngineeringFacility> findByPage(EngineeringFacilityPageInDTO dto);
+
+    /**
+     * 地图数据:与分页查询同一套筛选条件,不分页,仅返回带坐标的记录
+     */
+    List<EngineeringFacility> listForMap(EngineeringFacilityPageInDTO dto);
+
+    /**
+     * 筛选下拉项:设施类型、等级、管理单位的库内去重值
+     */
+    Map<String, List<String>> getFilterOptions();
 
     /**
      * 新增

+ 3 - 27
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/PipeNetworkInfoService.java

@@ -4,10 +4,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.zksy.drainage.domain.PipeNetworkInfo;
 
-import java.util.List;
-
 /**
  * 排水管网基础数据 Service接口
+ * <p>
+ * 旧表 psgw_pipe_network_info 已停止写入,仅保留分页查询供风险分析类页面使用;
+ * 新增 / 修改 / 删除 / 批量删除 / 设备绑定方法对应端点已移除,故一并清理。
  */
 public interface PipeNetworkInfoService extends IService<PipeNetworkInfo> {
 
@@ -16,29 +17,4 @@ public interface PipeNetworkInfoService extends IService<PipeNetworkInfo> {
      */
     Page<PipeNetworkInfo> findByPage(long pageNum, long pageSize,
                                      String name, String area, String networkType);
-
-    /**
-     * 新增
-     */
-    boolean saveEntity(PipeNetworkInfo entity);
-
-    /**
-     * 修改
-     */
-    boolean updateEntity(PipeNetworkInfo entity);
-
-    /**
-     * 删除
-     */
-    boolean removeEntity(String id);
-
-    /**
-     * 批量删除
-     */
-    boolean removeBatchEntity(List<String> ids);
-
-    /**
-     * 绑定设备到管网
-     */
-    boolean bindEquipment(String id, List<String> equipmentIds);
 }

+ 15 - 3
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/WaterloggingPointService.java

@@ -3,8 +3,10 @@ package com.zksy.drainage.service;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.zksy.drainage.domain.WaterloggingPoint;
+import com.zksy.drainage.dto.WaterloggingPointPageInDTO;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 易积水点管理 Service接口
@@ -14,7 +16,17 @@ public interface WaterloggingPointService extends IService<WaterloggingPoint> {
     /**
      * 分页查询
      */
-    Page<WaterloggingPoint> findByPage(long pageNum, long pageSize, String name, String area);
+    Page<WaterloggingPoint> findByPage(WaterloggingPointPageInDTO dto);
+
+    /**
+     * 地图数据:与分页查询同一套筛选条件,不分页,仅返回带坐标的记录
+     */
+    List<WaterloggingPoint> listForMap(WaterloggingPointPageInDTO dto);
+
+    /**
+     * 筛选下拉项:所属区域、积水程度的库内去重值
+     */
+    Map<String, List<String>> getFilterOptions();
 
     /**
      * 新增
@@ -37,7 +49,7 @@ public interface WaterloggingPointService extends IService<WaterloggingPoint> {
     boolean removeBatchWithCheck(List<String> ids);
 
     /**
-     * 绑定设备到易积水点
+     * 关联摄像头到易积水点(整体替换,传空列表表示解除全部关联)
      */
-    boolean bindEquipment(String id, List<String> equipmentIds);
+    boolean bindCameras(String pointId, List<String> cameraIds);
 }

+ 12 - 10
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/DrainageEquipmentBindingServiceImpl.java

@@ -57,19 +57,22 @@ public class DrainageEquipmentBindingServiceImpl implements DrainageEquipmentBin
         }
         for (EngineeringFacility item : engineeringFacilityMapper.selectList(
                 new LambdaQueryWrapper<EngineeringFacility>().select(
-                        EngineeringFacility::getId, EngineeringFacility::getName,
+                        EngineeringFacility::getFacilityId, EngineeringFacility::getFacilityName,
                         EngineeringFacility::getFacilityType, EngineeringFacility::getEquipmentId))) {
             // 泵站设施的 equipment_id 保存的是泵站ID,不属于监测设备关联。
-            if ("泵站".equals(item.getFacilityType())) {
+            if (EngineeringFacility.TYPE_PUMP.equals(item.getFacilityType())
+                    || "泵站".equals(item.getFacilityType())) {
                 continue;
             }
-            addBindings(result, TYPE_FACILITY, item.getId(), item.getName(), item.getEquipmentId(),
+            addBindings(result, TYPE_FACILITY, item.getFacilityId(), item.getFacilityName(), item.getEquipmentId(),
                     excludeType, excludeId, "工程设施");
         }
+        // 易积水点关联的是摄像头(equipment_base.equipment_type_id=20),同样参与占用校验
         for (WaterloggingPoint item : waterloggingPointMapper.selectList(
                 new LambdaQueryWrapper<WaterloggingPoint>().select(
-                        WaterloggingPoint::getId, WaterloggingPoint::getName, WaterloggingPoint::getEquipmentId))) {
-            addBindings(result, TYPE_WATERLOGGING, item.getId(), item.getName(), item.getEquipmentId(),
+                        WaterloggingPoint::getPointId, WaterloggingPoint::getPointName,
+                        WaterloggingPoint::getCameraIds))) {
+            addBindings(result, TYPE_WATERLOGGING, item.getPointId(), item.getPointName(), item.getCameraIds(),
                     excludeType, excludeId, "易积水点");
         }
         return result;
@@ -117,16 +120,15 @@ public class DrainageEquipmentBindingServiceImpl implements DrainageEquipmentBin
             case TYPE_FACILITY:
                 EngineeringFacility facility = engineeringFacilityMapper.selectById(sourceId);
                 if (facility == null) return false;
-                if ("泵站".equals(facility.getFacilityType())) {
+                if (EngineeringFacility.TYPE_PUMP.equals(facility.getFacilityType())
+                        || "泵站".equals(facility.getFacilityType())) {
                     throw new ServiceException("泵站设施请使用关联泵站功能");
                 }
                 facility.setEquipmentId(value);
                 return engineeringFacilityMapper.updateById(facility) > 0;
             case TYPE_WATERLOGGING:
-                WaterloggingPoint waterloggingPoint = waterloggingPointMapper.selectById(sourceId);
-                if (waterloggingPoint == null) return false;
-                waterloggingPoint.setEquipmentId(value);
-                return waterloggingPointMapper.updateById(waterloggingPoint) > 0;
+                // 易积水点关联的是摄像头,走 WaterloggingPointService.bindCameras,不再共用设备关联入口
+                throw new ServiceException("易积水点关联的是摄像头,请使用关联摄像头功能");
             default:
                 return false;
         }

+ 64 - 14
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/EngineeringFacilityServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.common.exception.ServiceException;
 import com.zksy.drainage.domain.EngineeringFacility;
+import com.zksy.drainage.dto.EngineeringFacilityPageInDTO;
 import com.zksy.drainage.mapper.EngineeringFacilityMapper;
 import com.zksy.drainage.service.DrainageEquipmentBindingService;
 import com.zksy.drainage.service.EngineeringFacilityService;
@@ -14,7 +15,10 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -29,21 +33,67 @@ public class EngineeringFacilityServiceImpl extends ServiceImpl<EngineeringFacil
     private DrainageEquipmentBindingService equipmentBindingService;
 
     @Override
-    public Page<EngineeringFacility> findByPage(long pageNum, long pageSize,
-                                                String name, String area, String facilityType) {
+    public Page<EngineeringFacility> findByPage(EngineeringFacilityPageInDTO dto) {
+        EngineeringFacilityPageInDTO query = dto == null ? new EngineeringFacilityPageInDTO() : dto;
+        long pageNum = query.getPageNum() == null || query.getPageNum() < 1 ? 1 : query.getPageNum();
+        long pageSize = query.getPageSize() == null || query.getPageSize() < 1 ? 10 : query.getPageSize();
         Page<EngineeringFacility> page = new Page<>(pageNum, pageSize);
+        return this.page(page, buildWrapper(query));
+    }
+
+    @Override
+    public List<EngineeringFacility> listForMap(EngineeringFacilityPageInDTO dto) {
+        EngineeringFacilityPageInDTO query = dto == null ? new EngineeringFacilityPageInDTO() : dto;
+        LambdaQueryWrapper<EngineeringFacility> wrapper = buildWrapper(query);
+        wrapper.isNotNull(EngineeringFacility::getLongitude)
+                .isNotNull(EngineeringFacility::getLatitude)
+                .orderByAsc(EngineeringFacility::getFacilityCode);
+        return this.list(wrapper);
+    }
+
+    @Override
+    public Map<String, List<String>> getFilterOptions() {
+        Map<String, List<String>> options = new LinkedHashMap<>();
+        options.put("facilityType", distinctValues(EngineeringFacility::getFacilityType));
+        options.put("facilityLevel", distinctValues(EngineeringFacility::getFacilityLevel));
+        options.put("managementUnit", distinctValues(EngineeringFacility::getManagementUnit));
+        options.put("status", distinctValues(EngineeringFacility::getStatus));
+        return options;
+    }
+
+    /**
+     * 分页与地图共用同一套筛选条件,避免「列表筛了、地图没筛」的口径漂移。
+     */
+    private LambdaQueryWrapper<EngineeringFacility> buildWrapper(EngineeringFacilityPageInDTO query) {
         LambdaQueryWrapper<EngineeringFacility> wrapper = new LambdaQueryWrapper<>();
-        if (name != null && !name.isEmpty()) {
-            wrapper.like(EngineeringFacility::getName, name);
-        }
-        if (area != null && !area.isEmpty()) {
-            wrapper.like(EngineeringFacility::getArea, area);
-        }
-        if (facilityType != null && !facilityType.isEmpty()) {
-            wrapper.eq(EngineeringFacility::getFacilityType, facilityType);
-        }
+        wrapper.like(hasText(query.getFacilityCode()), EngineeringFacility::getFacilityCode, query.getFacilityCode());
+        wrapper.like(hasText(query.getFacilityName()), EngineeringFacility::getFacilityName, query.getFacilityName());
+        wrapper.eq(hasText(query.getFacilityType()), EngineeringFacility::getFacilityType, query.getFacilityType());
+        wrapper.eq(hasText(query.getFacilityLevel()), EngineeringFacility::getFacilityLevel, query.getFacilityLevel());
+        wrapper.like(hasText(query.getManagementUnit()), EngineeringFacility::getManagementUnit, query.getManagementUnit());
+        wrapper.like(hasText(query.getLocation()), EngineeringFacility::getLocation, query.getLocation());
+        wrapper.eq(hasText(query.getStatus()), EngineeringFacility::getStatus, query.getStatus());
         wrapper.orderByDesc(EngineeringFacility::getCreateTime);
-        return this.page(page, wrapper);
+        return wrapper;
+    }
+
+    private boolean hasText(String value) {
+        return value != null && !value.trim().isEmpty();
+    }
+
+    private List<String> distinctValues(com.baomidou.mybatisplus.core.toolkit.support.SFunction<EngineeringFacility, ?> column) {
+        List<EngineeringFacility> rows = this.list(new LambdaQueryWrapper<EngineeringFacility>()
+                .select(column)
+                .isNotNull(column)
+                .groupBy(column));
+        List<String> values = new ArrayList<>(rows.size());
+        for (EngineeringFacility row : rows) {
+            Object value = column.apply(row);
+            if (value != null && !String.valueOf(value).trim().isEmpty()) {
+                values.add(String.valueOf(value).trim());
+            }
+        }
+        return values.stream().distinct().sorted().collect(Collectors.toList());
     }
 
     @Override
@@ -57,7 +107,7 @@ public class EngineeringFacilityServiceImpl extends ServiceImpl<EngineeringFacil
     @Override
     @Transactional
     public boolean updateEntity(EngineeringFacility entity) {
-        String id = entity.getId();
+        String id = entity.getFacilityId();
         if (this.getById(id) == null) {
             throw new ServiceException("工程设施不存在,无法修改:" + id);
         }
@@ -85,7 +135,7 @@ public class EngineeringFacilityServiceImpl extends ServiceImpl<EngineeringFacil
             throw new ServiceException("批量删除失败:所有ID均不存在");
         }
         List<String> existIds = existing.stream()
-                .map(EngineeringFacility::getId)
+                .map(EngineeringFacility::getFacilityId)
                 .collect(Collectors.toList());
         List<String> invalidIds = ids.stream()
                 .filter(id -> !existIds.contains(id))

+ 3 - 67
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/PipeNetworkInfoServiceImpl.java

@@ -1,33 +1,25 @@
 package com.zksy.drainage.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.zksy.common.exception.ServiceException;
 import com.zksy.drainage.domain.PipeNetworkInfo;
 import com.zksy.drainage.mapper.PipeNetworkInfoMapper;
-import com.zksy.drainage.service.DrainageEquipmentBindingService;
 import com.zksy.drainage.service.PipeNetworkInfoService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import java.time.LocalDateTime;
-import java.util.List;
-import java.util.stream.Collectors;
 
 /**
  * 排水管网基础数据 ServiceImpl
+ * <p>
+ * 旧表 psgw_pipe_network_info 已停止写入,仅保留分页查询。
+ * 增删改与设备绑定实现已随后端端点清理一并移除。
  */
 @Slf4j
 @Service
 public class PipeNetworkInfoServiceImpl extends ServiceImpl<PipeNetworkInfoMapper, PipeNetworkInfo>
         implements PipeNetworkInfoService {
 
-    @org.springframework.beans.factory.annotation.Autowired
-    private DrainageEquipmentBindingService equipmentBindingService;
-
     @Override
     public Page<PipeNetworkInfo> findByPage(long pageNum, long pageSize,
                                             String name, String area, String networkType) {
@@ -45,60 +37,4 @@ public class PipeNetworkInfoServiceImpl extends ServiceImpl<PipeNetworkInfoMappe
         wrapper.orderByDesc(PipeNetworkInfo::getCreateTime);
         return this.page(page, wrapper);
     }
-
-    @Override
-    @Transactional
-    public boolean saveEntity(PipeNetworkInfo entity) {
-        entity.setCreateTime(LocalDateTime.now());
-        entity.setUpdateTime(LocalDateTime.now());
-        return this.save(entity);
-    }
-
-    @Override
-    @Transactional
-    public boolean updateEntity(PipeNetworkInfo entity) {
-        String id = entity.getId();
-        if (this.getById(id) == null) {
-            throw new ServiceException("排水管网不存在,无法修改:" + id);
-        }
-        entity.setUpdateTime(LocalDateTime.now());
-        return this.updateById(entity);
-    }
-
-    @Override
-    @Transactional
-    public boolean removeEntity(String id) {
-        if (this.getById(id) == null) {
-            throw new ServiceException("排水管网不存在:" + id);
-        }
-        return this.baseMapper.deleteById(id) > 0;
-    }
-
-    @Override
-    @Transactional
-    public boolean removeBatchEntity(List<String> ids) {
-        if (CollectionUtils.isEmpty(ids)) {
-            throw new ServiceException("批量删除失败:ID列表不能为空");
-        }
-        List<PipeNetworkInfo> existing = this.listByIds(ids);
-        if (existing.isEmpty()) {
-            throw new ServiceException("批量删除失败:所有ID均不存在");
-        }
-        List<String> existIds = existing.stream()
-                .map(PipeNetworkInfo::getId)
-                .collect(Collectors.toList());
-        List<String> invalidIds = ids.stream()
-                .filter(id -> !existIds.contains(id))
-                .collect(Collectors.toList());
-        if (!invalidIds.isEmpty()) {
-            log.warn("批量删除中存在无效排水管网ID:{}", invalidIds);
-        }
-        return this.removeByIds(existIds);
-    }
-
-    @Override
-    public boolean bindEquipment(String id, List<String> equipmentIds) {
-        return equipmentBindingService.bindEquipment(
-                DrainageEquipmentBindingService.TYPE_PIPE_NETWORK, id, equipmentIds);
-    }
 }

+ 139 - 36
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/WaterloggingPointServiceImpl.java

@@ -2,18 +2,25 @@ package com.zksy.drainage.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.common.exception.ServiceException;
 import com.zksy.drainage.domain.WaterloggingPoint;
+import com.zksy.drainage.dto.WaterloggingPointPageInDTO;
 import com.zksy.drainage.mapper.WaterloggingPointMapper;
-import com.zksy.drainage.service.DrainageEquipmentBindingService;
 import com.zksy.drainage.service.WaterloggingPointService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -24,57 +31,144 @@ import java.util.stream.Collectors;
 public class WaterloggingPointServiceImpl extends ServiceImpl<WaterloggingPointMapper, WaterloggingPoint>
         implements WaterloggingPointService {
 
-    @org.springframework.beans.factory.annotation.Autowired
-    private DrainageEquipmentBindingService equipmentBindingService;
-
     @org.springframework.beans.factory.annotation.Autowired
     private com.zksy.drainage.mapper.DrainageBindingLockMapper bindingLock;
 
     @Override
-    public Page<WaterloggingPoint> findByPage(long pageNum, long pageSize, String name, String area) {
-        Page<WaterloggingPoint> page = new Page<>(pageNum, pageSize);
+    public Page<WaterloggingPoint> findByPage(WaterloggingPointPageInDTO dto) {
+        WaterloggingPointPageInDTO query = dto == null ? new WaterloggingPointPageInDTO() : dto;
+        long pageNum = query.getPageNum() == null || query.getPageNum() < 1 ? 1 : query.getPageNum();
+        long pageSize = query.getPageSize() == null || query.getPageSize() < 1 ? 10 : query.getPageSize();
+        return this.page(new Page<>(pageNum, pageSize), buildWrapper(query));
+    }
+
+    @Override
+    public List<WaterloggingPoint> listForMap(WaterloggingPointPageInDTO dto) {
+        WaterloggingPointPageInDTO query = dto == null ? new WaterloggingPointPageInDTO() : dto;
+        LambdaQueryWrapper<WaterloggingPoint> wrapper = buildWrapper(query);
+        wrapper.isNotNull(WaterloggingPoint::getLongitude)
+                .isNotNull(WaterloggingPoint::getLatitude)
+                .orderByAsc(WaterloggingPoint::getPointCode);
+        return this.list(wrapper);
+    }
+
+    @Override
+    public Map<String, List<String>> getFilterOptions() {
+        Map<String, List<String>> options = new LinkedHashMap<>();
+        options.put("district", distinctValues(WaterloggingPoint::getDistrict));
+        options.put("waterloggingLevel", distinctValues(WaterloggingPoint::getWaterloggingLevel));
+        options.put("riskLevel", distinctValues(WaterloggingPoint::getRiskLevel));
+        return options;
+    }
+
+    /**
+     * 分页与地图共用同一套筛选条件,避免口径漂移。
+     */
+    private LambdaQueryWrapper<WaterloggingPoint> buildWrapper(WaterloggingPointPageInDTO query) {
         LambdaQueryWrapper<WaterloggingPoint> wrapper = new LambdaQueryWrapper<>();
-        if (name != null && !name.isEmpty()) {
-            wrapper.like(WaterloggingPoint::getName, name);
-        }
-        if (area != null && !area.isEmpty()) {
-            wrapper.like(WaterloggingPoint::getArea, area);
-        }
+        wrapper.like(hasText(query.getPointCode()), WaterloggingPoint::getPointCode, query.getPointCode());
+        wrapper.like(hasText(query.getPointName()), WaterloggingPoint::getPointName, query.getPointName());
+        wrapper.like(hasText(query.getDistrict()), WaterloggingPoint::getDistrict, query.getDistrict());
+        wrapper.eq(query.getWaterloggingLevel() != null,
+                WaterloggingPoint::getWaterloggingLevel, query.getWaterloggingLevel());
+        wrapper.eq(hasText(query.getRiskLevel()), WaterloggingPoint::getRiskLevel, query.getRiskLevel());
         wrapper.orderByDesc(WaterloggingPoint::getCreateTime);
-        return this.page(page, wrapper);
+        return wrapper;
+    }
+
+    private boolean hasText(String value) {
+        return value != null && !value.trim().isEmpty();
+    }
+
+    private List<String> distinctValues(SFunction<WaterloggingPoint, ?> column) {
+        List<WaterloggingPoint> rows = this.list(new LambdaQueryWrapper<WaterloggingPoint>()
+                .select(column)
+                .isNotNull(column)
+                .groupBy(column));
+        List<String> values = new ArrayList<>(rows.size());
+        for (WaterloggingPoint row : rows) {
+            Object value = column.apply(row);
+            if (value != null && !String.valueOf(value).trim().isEmpty()) {
+                values.add(String.valueOf(value).trim());
+            }
+        }
+        return values.stream().distinct().sorted().collect(Collectors.toList());
     }
 
     @Override
     @Transactional
     public boolean saveWithCheck(WaterloggingPoint entity) {
         bindingLock.lock();
-        String equipmentIds = entity.getEquipmentId();
-        entity.setEquipmentId("");
+        String cameraIds = entity.getCameraIds();
+        entity.setCameraIds(null);
+        entity.setCreateTime(LocalDateTime.now());
+        entity.setUpdateTime(LocalDateTime.now());
         if (!this.save(entity)) return false;
-        if (equipmentIds != null && !equipmentIds.isBlank())
-            equipmentBindingService.bindEquipment(DrainageEquipmentBindingService.TYPE_WATERLOGGING,
-                    entity.getId(), java.util.Arrays.asList(equipmentIds.split(",")));
-        return true;
+        return applyCameras(entity.getPointId(), cameraIds);
     }
 
     @Override
     @Transactional
     public boolean updateWithCheck(WaterloggingPoint entity) {
         bindingLock.lock();
-        String id = entity.getId();
-        if (this.getById(id) == null) {
-            throw new ServiceException("易积水点不存在,无法修改:" + id);
+        String pointId = entity.getPointId();
+        if (this.getById(pointId) == null) {
+            throw new ServiceException("易积水点不存在,无法修改:" + pointId);
         }
-        String equipmentIds = entity.getEquipmentId();
-        entity.setEquipmentId(null);
+        String cameraIds = entity.getCameraIds();
+        entity.setCameraIds(null);
+        entity.setUpdateTime(LocalDateTime.now());
         if (!this.updateById(entity)) return false;
-        if (equipmentIds != null && !equipmentIds.isBlank())
-            equipmentBindingService.bindEquipment(DrainageEquipmentBindingService.TYPE_WATERLOGGING,
-                    id, java.util.Arrays.asList(equipmentIds.split(",")));
-        else if (equipmentIds != null)
-            this.baseMapper.update(null, new com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper<WaterloggingPoint>()
-                    .eq(WaterloggingPoint::getId, id).set(WaterloggingPoint::getEquipmentId, ""));
-        return true;
+        // cameraIds 传 null 表示本次不动关联;传空串表示解除全部关联
+        if (cameraIds == null) return true;
+        return applyCameras(pointId, cameraIds);
+    }
+
+    /**
+     * 整体替换某点位的摄像头关联,并校验摄像头是否已被其他点位占用。
+     */
+    private boolean applyCameras(String pointId, String cameraIds) {
+        List<String> normalized = parseIds(cameraIds);
+        checkCameraOccupation(pointId, normalized);
+        WaterloggingPoint patch = new WaterloggingPoint();
+        patch.setPointId(pointId);
+        patch.setCameraIds(String.join(",", normalized));
+        patch.setUpdateTime(LocalDateTime.now());
+        return this.updateById(patch);
+    }
+
+    @Override
+    @Transactional
+    public boolean bindCameras(String pointId, List<String> cameraIds) {
+        bindingLock.lock();
+        if (this.getById(pointId) == null) {
+            throw new ServiceException("易积水点不存在:" + pointId);
+        }
+        List<String> normalized = normalizeIds(cameraIds);
+        checkCameraOccupation(pointId, normalized);
+        WaterloggingPoint patch = new WaterloggingPoint();
+        patch.setPointId(pointId);
+        patch.setCameraIds(String.join(",", normalized));
+        patch.setUpdateTime(LocalDateTime.now());
+        return this.updateById(patch);
+    }
+
+    /** 摄像头只能挂在一个易积水点上,避免摄像头不在现场却出现在两个点位。 */
+    private void checkCameraOccupation(String pointId, List<String> cameraIds) {
+        if (cameraIds.isEmpty()) return;
+        List<WaterloggingPoint> others = this.list(new LambdaQueryWrapper<WaterloggingPoint>()
+                .ne(WaterloggingPoint::getPointId, pointId)
+                .isNotNull(WaterloggingPoint::getCameraIds));
+        for (WaterloggingPoint other : others) {
+            Set<String> occupied = parseIds(other.getCameraIds()).stream()
+                    .collect(Collectors.toCollection(LinkedHashSet::new));
+            for (String cameraId : cameraIds) {
+                if (occupied.contains(cameraId)) {
+                    String name = hasText(other.getPointName()) ? other.getPointName() : other.getPointId();
+                    throw new ServiceException("摄像头已被易积水点「" + name + "」关联,请先解除");
+                }
+            }
+        }
     }
 
     @Override
@@ -99,14 +193,23 @@ public class WaterloggingPointServiceImpl extends ServiceImpl<WaterloggingPointM
             throw new ServiceException("批量删除失败:所有ID均不存在");
         }
         List<String> existIds = existing.stream()
-                .map(WaterloggingPoint::getId)
+                .map(WaterloggingPoint::getPointId)
                 .collect(Collectors.toList());
         return this.removeByIds(existIds);
     }
 
-    @Override
-    public boolean bindEquipment(String id, List<String> equipmentIds) {
-        return equipmentBindingService.bindEquipment(
-                DrainageEquipmentBindingService.TYPE_WATERLOGGING, id, equipmentIds);
+    private List<String> parseIds(String value) {
+        if (value == null || value.trim().isEmpty()) return new ArrayList<>();
+        return normalizeIds(java.util.Arrays.asList(value.split(",")));
+    }
+
+    private List<String> normalizeIds(List<String> ids) {
+        if (ids == null) return new ArrayList<>();
+        return ids.stream()
+                .filter(java.util.Objects::nonNull)
+                .map(String::trim)
+                .filter(s -> !s.isEmpty())
+                .distinct()
+                .collect(Collectors.toList());
     }
 }