|
|
@@ -5,6 +5,14 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
import com.zksy.base.domain.PipeNetworkBase;
|
|
|
import com.zksy.base.domain.RiskAssessment;
|
|
|
+import com.zksy.base.domain.GasPipePoint;
|
|
|
+import com.zksy.base.domain.GasPipePointDeviceRel;
|
|
|
+import com.zksy.base.domain.EquipmentBase;
|
|
|
+import com.zksy.base.alarm.domain.AlarmData;
|
|
|
+import com.zksy.base.mapper.GasPipePointMapper;
|
|
|
+import com.zksy.base.mapper.GasPipePointDeviceRelMapper;
|
|
|
+import com.zksy.base.mapper.EquipmentBaseMapper;
|
|
|
+import com.zksy.base.alarm.mapper.AlarmDataMapper;
|
|
|
import com.zksy.base.dto.RiskPageInDTO;
|
|
|
import com.zksy.base.mapper.PipeNetworkBaseMapper;
|
|
|
import com.zksy.base.mapper.RiskAssessmentMapper;
|
|
|
@@ -14,6 +22,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.util.*;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Slf4j
|
|
|
@@ -24,6 +36,18 @@ public class RiskAssessmentServiceImpl extends ServiceImpl<RiskAssessmentMapper,
|
|
|
@Autowired
|
|
|
private PipeNetworkBaseMapper pipeNetworkBaseMapper;
|
|
|
|
|
|
+ @Autowired
|
|
|
+ private GasPipePointMapper gasPipePointMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private GasPipePointDeviceRelMapper gasPipePointDeviceRelMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EquipmentBaseMapper equipmentBaseMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private AlarmDataMapper alarmDataMapper;
|
|
|
+
|
|
|
@Override
|
|
|
public Page<RiskAssessment> findByPage(RiskPageInDTO dto) {
|
|
|
Page<RiskAssessment> page = new Page<>(dto.getPageNum(), dto.getPageSize());
|
|
|
@@ -72,4 +96,115 @@ public class RiskAssessmentServiceImpl extends ServiceImpl<RiskAssessmentMapper,
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Map<String, Object>> getGasRiskAssessments() {
|
|
|
+ List<PipeNetworkBase> networks = pipeNetworkBaseMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<PipeNetworkBase>()
|
|
|
+ .and(w -> w.in(PipeNetworkBase::getNetworkType, "gas", "GAS", "Gas", "燃气", "燃气管网")
|
|
|
+ .or().like(PipeNetworkBase::getNetworkName, "燃气"))
|
|
|
+ .orderByDesc(PipeNetworkBase::getCreateTime));
|
|
|
+ if (networks.isEmpty()) return Collections.emptyList();
|
|
|
+
|
|
|
+ Set<String> networkIds = networks.stream().map(PipeNetworkBase::getNetworkId)
|
|
|
+ .filter(Objects::nonNull).collect(Collectors.toSet());
|
|
|
+ List<GasPipePoint> points = gasPipePointMapper.selectList(new LambdaQueryWrapper<GasPipePoint>()
|
|
|
+ .in(GasPipePoint::getNetworkId, networkIds));
|
|
|
+ Set<Long> pointIds = points.stream().map(GasPipePoint::getPointId)
|
|
|
+ .filter(Objects::nonNull).collect(Collectors.toSet());
|
|
|
+ List<GasPipePointDeviceRel> rels = pointIds.isEmpty() ? Collections.emptyList() :
|
|
|
+ gasPipePointDeviceRelMapper.selectList(new LambdaQueryWrapper<GasPipePointDeviceRel>()
|
|
|
+ .in(GasPipePointDeviceRel::getPointId, pointIds)
|
|
|
+ .eq(GasPipePointDeviceRel::getDelFlag, "0"));
|
|
|
+
|
|
|
+ Map<String, String> equipmentToNetwork = new HashMap<>();
|
|
|
+ Map<Long, String> pointNetwork = points.stream().collect(Collectors.toMap(
|
|
|
+ GasPipePoint::getPointId, GasPipePoint::getNetworkId, (a, b) -> a));
|
|
|
+ Set<String> equipmentIds = rels.stream().map(GasPipePointDeviceRel::getEquipmentId)
|
|
|
+ .filter(Objects::nonNull).collect(Collectors.toSet());
|
|
|
+ if (!equipmentIds.isEmpty()) {
|
|
|
+ List<EquipmentBase> equipment = equipmentBaseMapper.selectBatchIds(equipmentIds);
|
|
|
+ Map<String, String> idToCode = equipment.stream().collect(Collectors.toMap(
|
|
|
+ EquipmentBase::getEquipmentId, EquipmentBase::getEquipmentCode, (a, b) -> a));
|
|
|
+ for (GasPipePointDeviceRel rel : rels) {
|
|
|
+ String code = idToCode.get(rel.getEquipmentId());
|
|
|
+ String networkId = pointNetwork.get(rel.getPointId());
|
|
|
+ if (code != null && networkId != null) equipmentToNetwork.put(code, networkId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime since = LocalDateTime.now().minusDays(30);
|
|
|
+ List<AlarmData> alarms = equipmentToNetwork.isEmpty() ? Collections.emptyList() :
|
|
|
+ alarmDataMapper.selectList(new LambdaQueryWrapper<AlarmData>()
|
|
|
+ .in(AlarmData::getDeviceCode, equipmentToNetwork.keySet())
|
|
|
+ .ge(AlarmData::getAlarmTime, since));
|
|
|
+ Map<String, List<AlarmData>> alarmsByNetwork = new HashMap<>();
|
|
|
+ for (AlarmData alarm : alarms) {
|
|
|
+ String networkId = equipmentToNetwork.get(alarm.getDeviceCode());
|
|
|
+ if (networkId != null) alarmsByNetwork.computeIfAbsent(networkId, k -> new ArrayList<>()).add(alarm);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Map<String, Object>> result = new ArrayList<>();
|
|
|
+ for (PipeNetworkBase pipe : networks) {
|
|
|
+ List<AlarmData> networkAlarms = alarmsByNetwork.getOrDefault(pipe.getNetworkId(), Collections.emptyList());
|
|
|
+ int ageScore = ageScore(pipe.getBuildDate());
|
|
|
+ int alarmScore = alarmFrequencyScore(networkAlarms.size());
|
|
|
+ int unresolvedScore = (int) Math.min(20, networkAlarms.stream()
|
|
|
+ .filter(a -> Objects.equals(a.getAlarmStatus(), 0)).count() * 5);
|
|
|
+ int highLevelScore = (int) Math.min(15, networkAlarms.stream()
|
|
|
+ .filter(a -> a.getAlarmLevel() != null && a.getAlarmLevel() <= 2).count() * 5);
|
|
|
+ int pressureScore = pressureScore(pipe.getNetworkLevel());
|
|
|
+ int materialScore = "钢管".equals(pipe.getMaterial()) ? 5 : 2;
|
|
|
+ int score = Math.min(100, ageScore + alarmScore + unresolvedScore + highLevelScore + pressureScore + materialScore);
|
|
|
+ String level = score >= 70 ? "high" : score >= 40 ? "medium" : "low";
|
|
|
+
|
|
|
+ Map<String, Object> item = new LinkedHashMap<>();
|
|
|
+ item.put("id", pipe.getNetworkId());
|
|
|
+ item.put("networkId", pipe.getNetworkId());
|
|
|
+ item.put("code", pipe.getNetworkCode());
|
|
|
+ item.put("name", pipe.getNetworkName());
|
|
|
+ item.put("area", pipe.getLocation());
|
|
|
+ item.put("material", pipe.getMaterial());
|
|
|
+ item.put("diameter", pipe.getDiameter());
|
|
|
+ item.put("length", pipe.getLength() == null ? null : pipe.getLength().doubleValue() / 1000d);
|
|
|
+ item.put("buildYear", pipe.getBuildDate() == null ? null : pipe.getBuildDate().toInstant().atZone(ZoneId.systemDefault()).getYear());
|
|
|
+ item.put("pressure", pressureValue(pipe.getNetworkLevel()));
|
|
|
+ item.put("pressureLevel", pipe.getNetworkLevel());
|
|
|
+ item.put("owner", pipe.getManagementUnit());
|
|
|
+ item.put("lastInspection", null);
|
|
|
+ // 同步返回管网起终点坐标,当前端 GIS 图层接口暂时无法按编号匹配时,
|
|
|
+ // 仍可直接使用风险评估结果绘制管线。
|
|
|
+ item.put("startLongitude", pipe.getStartLongitude());
|
|
|
+ item.put("startLatitude", pipe.getStartLatitude());
|
|
|
+ item.put("endLongitude", pipe.getEndLongitude());
|
|
|
+ item.put("endLatitude", pipe.getEndLatitude());
|
|
|
+ item.put("riskLevel", level);
|
|
|
+ item.put("riskScore", score);
|
|
|
+ item.put("dimensions", dimensions(ageScore, alarmScore, unresolvedScore + highLevelScore, pressureScore, materialScore));
|
|
|
+ List<String> factors = new ArrayList<>();
|
|
|
+ if (ageScore >= 15) factors.add("管网使用年限较长(" + ageYears(pipe.getBuildDate()) + "年)");
|
|
|
+ if (!networkAlarms.isEmpty()) factors.add("近30天发生" + networkAlarms.size() + "次报警");
|
|
|
+ if (unresolvedScore > 0) factors.add("存在" + unresolvedScore / 5 + "条未处理报警");
|
|
|
+ if (highLevelScore > 0) factors.add("存在高等级报警");
|
|
|
+ if (factors.isEmpty()) factors.add("近30天无报警,基础资料风险较低");
|
|
|
+ item.put("riskFactors", factors);
|
|
|
+ item.put("mitigationMeasures", Arrays.asList("按风险等级安排巡检频次", "持续补充管网检测和维修记录"));
|
|
|
+ item.put("historyRecords", Collections.emptyList());
|
|
|
+ item.put("attachments", Collections.emptyList());
|
|
|
+ result.add(item);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private int ageYears(Date date) {
|
|
|
+ if (date == null) return 0;
|
|
|
+ return Math.max(0, LocalDate.now().getYear() - date.toInstant().atZone(ZoneId.systemDefault()).getYear());
|
|
|
+ }
|
|
|
+ private int ageScore(Date date) { int age = ageYears(date); return age == 0 ? 0 : age <= 5 ? 5 : age <= 10 ? 15 : age <= 15 ? 22 : 30; }
|
|
|
+ private int alarmFrequencyScore(int count) { return count == 0 ? 0 : count <= 2 ? 10 : count <= 5 ? 20 : 30; }
|
|
|
+ private int pressureScore(String level) { if (level == null) return 0; return level.contains("高") || level.toLowerCase().contains("high") ? 20 : level.contains("中") || level.toLowerCase().contains("medium") ? 12 : 5; }
|
|
|
+ private String pressureValue(String level) { if (level == null) return null; if (level.contains("高")) return "1.6"; if (level.contains("中")) return "0.4"; if (level.contains("低")) return "0.1"; return null; }
|
|
|
+ private Map<String, Integer> dimensions(int age, int alarms, int severity, int pressure, int material) {
|
|
|
+ Map<String, Integer> d = new LinkedHashMap<>(); d.put("leakProbability", Math.min(100, alarms * 3 + age * 2)); d.put("consequenceSeverity", Math.min(100, pressure * 4 + severity * 2)); d.put("corrosionRisk", Math.min(100, age * 3 + material * 4)); d.put("thirdPartyRisk", Math.min(100, alarms * 2 + pressure * 2)); d.put("agingLevel", Math.min(100, age * 3)); return d;
|
|
|
+ }
|
|
|
}
|