LAPTOP-JI2IUVG1\26646 1 bulan lalu
induk
melakukan
c103f44cbb

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

@@ -13,6 +13,7 @@ import com.zksy.common.annotation.Log;
 import com.zksy.common.core.domain.AjaxResult;
 import com.zksy.common.enums.BusinessType;
 import com.zksy.drainage.service.DrainageEquipmentPointRelService;
+import com.zksy.drainage.service.DrainageEquipmentBindingService;
 import com.zksy.drainage.service.DrainageEquipmentTestService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -52,8 +53,20 @@ public class DrainageEquipmentController {
     @Autowired
     private DrainageEquipmentPointRelService equipmentPointRelService;
 
+    @Autowired
+    private DrainageEquipmentBindingService equipmentBindingService;
+
     // ==================== 设备基础信息 ====================
 
+    @Anonymous
+    @GetMapping("/boundEquipmentIds")
+    @ApiOperation(value = "查询排水基础数据中已占用的设备")
+    public AjaxResult boundEquipmentIds(
+            @ApiParam("排除的对象类型") @RequestParam(value = "excludeType", required = false) String excludeType,
+            @ApiParam("排除的对象ID") @RequestParam(value = "excludeId", required = false) String excludeId) {
+        return AjaxResult.success(equipmentBindingService.findBoundEquipment(excludeType, excludeId));
+    }
+
     @Anonymous
     @GetMapping("/base/page")
     @ApiOperation(value = "监测设备分页查询")

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

@@ -124,8 +124,7 @@ public class EngineeringFacilityController {
         if (facilityId == null || pumpStationIds == null || pumpStationIds.isEmpty()) {
             return AjaxResult.error("参数不完整");
         }
-        // 复用bindEquipment,直接存储泵站ID到equipmentId字段,不做设备表校验
-        boolean success = service.bindEquipment(facilityId, pumpStationIds);
+        boolean success = service.bindPumpStation(facilityId, pumpStationIds);
         return success ? AjaxResult.success("关联成功") : AjaxResult.error("关联失败");
     }
 }

+ 20 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/DrainageEquipmentBindingService.java

@@ -0,0 +1,20 @@
+package com.zksy.drainage.service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 排水基础数据设备关联服务。
+ * 同一监测设备在排水分区、排水管网、工程设施和易积水点中只能关联一个对象。
+ */
+public interface DrainageEquipmentBindingService {
+
+    String TYPE_PARTITION = "partition";
+    String TYPE_PIPE_NETWORK = "pipeNetwork";
+    String TYPE_FACILITY = "facility";
+    String TYPE_WATERLOGGING = "waterlogging";
+
+    Map<String, String> findBoundEquipment(String excludeType, String excludeId);
+
+    boolean bindEquipment(String sourceType, String sourceId, List<String> equipmentIds);
+}

+ 3 - 0
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/EngineeringFacilityService.java

@@ -41,4 +41,7 @@ public interface EngineeringFacilityService extends IService<EngineeringFacility
      * 绑定设备到工程设施
      */
     boolean bindEquipment(String id, List<String> equipmentIds);
+
+    /** 关联排水泵站;泵站不是监测设备,不参与设备唯一占用校验。 */
+    boolean bindPumpStation(String id, List<String> pumpStationIds);
 }

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

@@ -0,0 +1,182 @@
+package com.zksy.drainage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.zksy.common.exception.ServiceException;
+import com.zksy.drainage.domain.DrainagePartition;
+import com.zksy.drainage.domain.EngineeringFacility;
+import com.zksy.drainage.domain.PipeNetworkInfo;
+import com.zksy.drainage.domain.WaterloggingPoint;
+import com.zksy.drainage.mapper.DrainagePartitionMapper;
+import com.zksy.drainage.mapper.EngineeringFacilityMapper;
+import com.zksy.drainage.mapper.PipeNetworkInfoMapper;
+import com.zksy.drainage.mapper.WaterloggingPointMapper;
+import com.zksy.drainage.service.DrainageEquipmentBindingService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** 排水设备全局唯一关联实现。 */
+@Service
+public class DrainageEquipmentBindingServiceImpl implements DrainageEquipmentBindingService {
+
+    @Autowired
+    private DrainagePartitionMapper drainagePartitionMapper;
+
+    @Autowired
+    private PipeNetworkInfoMapper pipeNetworkInfoMapper;
+
+    @Autowired
+    private EngineeringFacilityMapper engineeringFacilityMapper;
+
+    @Autowired
+    private WaterloggingPointMapper waterloggingPointMapper;
+
+    @Override
+    public Map<String, String> findBoundEquipment(String excludeType, String excludeId) {
+        validateSourceType(excludeType, true);
+        Map<String, String> result = new LinkedHashMap<>();
+
+        for (DrainagePartition item : drainagePartitionMapper.selectList(
+                new LambdaQueryWrapper<DrainagePartition>().select(
+                        DrainagePartition::getId, DrainagePartition::getName, DrainagePartition::getEquipmentId))) {
+            addBindings(result, TYPE_PARTITION, item.getId(), item.getName(), item.getEquipmentId(),
+                    excludeType, excludeId, "排水分区");
+        }
+        for (PipeNetworkInfo item : pipeNetworkInfoMapper.selectList(
+                new LambdaQueryWrapper<PipeNetworkInfo>().select(
+                        PipeNetworkInfo::getId, PipeNetworkInfo::getName, PipeNetworkInfo::getEquipmentId))) {
+            addBindings(result, TYPE_PIPE_NETWORK, item.getId(), item.getName(), item.getEquipmentId(),
+                    excludeType, excludeId, "排水管网");
+        }
+        for (EngineeringFacility item : engineeringFacilityMapper.selectList(
+                new LambdaQueryWrapper<EngineeringFacility>().select(
+                        EngineeringFacility::getId, EngineeringFacility::getName,
+                        EngineeringFacility::getFacilityType, EngineeringFacility::getEquipmentId))) {
+            // 泵站设施的 equipment_id 保存的是泵站ID,不属于监测设备关联。
+            if ("泵站".equals(item.getFacilityType())) {
+                continue;
+            }
+            addBindings(result, TYPE_FACILITY, item.getId(), item.getName(), item.getEquipmentId(),
+                    excludeType, excludeId, "工程设施");
+        }
+        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(),
+                    excludeType, excludeId, "易积水点");
+        }
+        return result;
+    }
+
+    /** 同一个服务实例串行完成检查和保存,防止单实例内并发抢占同一设备。 */
+    @Override
+    @Transactional
+    public synchronized boolean bindEquipment(String sourceType, String sourceId, List<String> equipmentIds) {
+        validateSourceType(sourceType, false);
+        if (sourceId == null || sourceId.trim().isEmpty()) {
+            throw new ServiceException("关联对象ID不能为空");
+        }
+
+        List<String> normalizedIds = normalizeEquipmentIds(equipmentIds);
+        if (normalizedIds.isEmpty()) {
+            throw new ServiceException("请选择要关联的设备");
+        }
+
+        Map<String, String> occupied = findBoundEquipment(sourceType, sourceId);
+        List<String> conflicts = new ArrayList<>();
+        for (String equipmentId : normalizedIds) {
+            String sourceName = occupied.get(equipmentId);
+            if (sourceName != null) {
+                conflicts.add(equipmentId + "(" + sourceName + ")");
+            }
+        }
+        if (!conflicts.isEmpty()) {
+            throw new ServiceException("设备已被其他位置关联,不能重复关联:" + String.join("、", conflicts));
+        }
+
+        String value = String.join(",", normalizedIds);
+        switch (sourceType) {
+            case TYPE_PARTITION:
+                DrainagePartition partition = drainagePartitionMapper.selectById(sourceId);
+                if (partition == null) return false;
+                partition.setEquipmentId(value);
+                return drainagePartitionMapper.updateById(partition) > 0;
+            case TYPE_PIPE_NETWORK:
+                PipeNetworkInfo pipeNetwork = pipeNetworkInfoMapper.selectById(sourceId);
+                if (pipeNetwork == null) return false;
+                pipeNetwork.setEquipmentId(value);
+                return pipeNetworkInfoMapper.updateById(pipeNetwork) > 0;
+            case TYPE_FACILITY:
+                EngineeringFacility facility = engineeringFacilityMapper.selectById(sourceId);
+                if (facility == null) return false;
+                if ("泵站".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;
+            default:
+                return false;
+        }
+    }
+
+    private void addBindings(Map<String, String> result, String sourceType, String sourceId,
+                             String sourceName, String equipmentIds, String excludeType,
+                             String excludeId, String sourceLabel) {
+        if (sourceType.equals(excludeType) && sourceId != null && sourceId.equals(excludeId)) {
+            return;
+        }
+        for (String equipmentId : splitEquipmentIds(equipmentIds)) {
+            String displayName = sourceName == null || sourceName.trim().isEmpty() ? sourceId : sourceName;
+            result.putIfAbsent(equipmentId, sourceLabel + " / " + displayName);
+        }
+    }
+
+    private List<String> normalizeEquipmentIds(List<String> equipmentIds) {
+        Set<String> result = new LinkedHashSet<>();
+        if (equipmentIds != null) {
+            for (String equipmentId : equipmentIds) {
+                if (equipmentId != null && !equipmentId.trim().isEmpty()) {
+                    result.add(equipmentId.trim());
+                }
+            }
+        }
+        return new ArrayList<>(result);
+    }
+
+    private List<String> splitEquipmentIds(String equipmentIds) {
+        List<String> result = new ArrayList<>();
+        if (equipmentIds == null || equipmentIds.trim().isEmpty()) {
+            return result;
+        }
+        for (String equipmentId : equipmentIds.split(",")) {
+            if (!equipmentId.trim().isEmpty()) {
+                result.add(equipmentId.trim());
+            }
+        }
+        return result;
+    }
+
+    private void validateSourceType(String sourceType, boolean allowEmpty) {
+        if (allowEmpty && (sourceType == null || sourceType.trim().isEmpty())) {
+            return;
+        }
+        if (!TYPE_PARTITION.equals(sourceType)
+                && !TYPE_PIPE_NETWORK.equals(sourceType)
+                && !TYPE_FACILITY.equals(sourceType)
+                && !TYPE_WATERLOGGING.equals(sourceType)) {
+            throw new ServiceException("不支持的排水设备关联类型:" + sourceType);
+        }
+    }
+}

+ 6 - 4
pipe-network-service/zksy-system/src/main/java/com/zksy/drainage/service/impl/DrainagePartitionServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.common.exception.ServiceException;
 import com.zksy.drainage.domain.DrainagePartition;
 import com.zksy.drainage.mapper.DrainagePartitionMapper;
+import com.zksy.drainage.service.DrainageEquipmentBindingService;
 import com.zksy.drainage.service.DrainagePartitionService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -23,6 +24,9 @@ import java.util.stream.Collectors;
 public class DrainagePartitionServiceImpl extends ServiceImpl<DrainagePartitionMapper, DrainagePartition>
         implements DrainagePartitionService {
 
+    @org.springframework.beans.factory.annotation.Autowired
+    private DrainageEquipmentBindingService equipmentBindingService;
+
     @Override
     public Page<DrainagePartition> findByPage(long pageNum, long pageSize,
                                               String name, String district, String partitionType) {
@@ -104,9 +108,7 @@ public class DrainagePartitionServiceImpl extends ServiceImpl<DrainagePartitionM
 
     @Override
     public boolean bindEquipment(String partitionId, List<String> equipmentIds) {
-        DrainagePartition partition = this.getById(partitionId);
-        if (partition == null) return false;
-        partition.setEquipmentId(String.join(",", equipmentIds));
-        return this.updateById(partition);
+        return equipmentBindingService.bindEquipment(
+                DrainageEquipmentBindingService.TYPE_PARTITION, partitionId, equipmentIds);
     }
 }

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

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.common.exception.ServiceException;
 import com.zksy.drainage.domain.EngineeringFacility;
 import com.zksy.drainage.mapper.EngineeringFacilityMapper;
+import com.zksy.drainage.service.DrainageEquipmentBindingService;
 import com.zksy.drainage.service.EngineeringFacilityService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -24,6 +25,9 @@ import java.util.stream.Collectors;
 public class EngineeringFacilityServiceImpl extends ServiceImpl<EngineeringFacilityMapper, EngineeringFacility>
         implements EngineeringFacilityService {
 
+    @org.springframework.beans.factory.annotation.Autowired
+    private DrainageEquipmentBindingService equipmentBindingService;
+
     @Override
     public Page<EngineeringFacility> findByPage(long pageNum, long pageSize,
                                                 String name, String area, String facilityType) {
@@ -94,9 +98,15 @@ public class EngineeringFacilityServiceImpl extends ServiceImpl<EngineeringFacil
 
     @Override
     public boolean bindEquipment(String id, List<String> equipmentIds) {
+        return equipmentBindingService.bindEquipment(
+                DrainageEquipmentBindingService.TYPE_FACILITY, id, equipmentIds);
+    }
+
+    @Override
+    public boolean bindPumpStation(String id, List<String> pumpStationIds) {
         EngineeringFacility entity = this.getById(id);
         if (entity == null) return false;
-        entity.setEquipmentId(String.join(",", equipmentIds));
+        entity.setEquipmentId(String.join(",", pumpStationIds));
         return this.updateById(entity);
     }
 }

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

@@ -7,6 +7,7 @@ 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;
@@ -24,6 +25,9 @@ import java.util.stream.Collectors;
 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) {
@@ -94,9 +98,7 @@ public class PipeNetworkInfoServiceImpl extends ServiceImpl<PipeNetworkInfoMappe
 
     @Override
     public boolean bindEquipment(String id, List<String> equipmentIds) {
-        PipeNetworkInfo entity = this.getById(id);
-        if (entity == null) return false;
-        entity.setEquipmentId(String.join(",", equipmentIds));
-        return this.updateById(entity);
+        return equipmentBindingService.bindEquipment(
+                DrainageEquipmentBindingService.TYPE_PIPE_NETWORK, id, equipmentIds);
     }
 }

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

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.common.exception.ServiceException;
 import com.zksy.drainage.domain.WaterloggingPoint;
 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;
@@ -23,6 +24,9 @@ import java.util.stream.Collectors;
 public class WaterloggingPointServiceImpl extends ServiceImpl<WaterloggingPointMapper, WaterloggingPoint>
         implements WaterloggingPointService {
 
+    @org.springframework.beans.factory.annotation.Autowired
+    private DrainageEquipmentBindingService equipmentBindingService;
+
     @Override
     public Page<WaterloggingPoint> findByPage(long pageNum, long pageSize, String name, String area) {
         Page<WaterloggingPoint> page = new Page<>(pageNum, pageSize);
@@ -80,9 +84,7 @@ public class WaterloggingPointServiceImpl extends ServiceImpl<WaterloggingPointM
 
     @Override
     public boolean bindEquipment(String id, List<String> equipmentIds) {
-        WaterloggingPoint entity = this.getById(id);
-        if (entity == null) return false;
-        entity.setEquipmentId(String.join(",", equipmentIds));
-        return this.updateById(entity);
+        return equipmentBindingService.bindEquipment(
+                DrainageEquipmentBindingService.TYPE_WATERLOGGING, id, equipmentIds);
     }
 }