lisonglin 2 долоо хоног өмнө
parent
commit
b3bf6b031e

+ 53 - 27
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SeAlarmServiceImpl.java

@@ -59,8 +59,8 @@ public class SeAlarmServiceImpl implements SeAlarmService {
 
     @Override
     public PageResult<SeAlarmListVO> queryOverloadAlarmList(String id, Integer type, String feederName,
-                                                             String startDate, String endDate, String orderDir,
-                                                             Integer page, Integer pageSize) {
+                                                            String startDate, String endDate, String orderDir,
+                                                            Integer page, Integer pageSize) {
         if (page == null || page < 1) page = 1;
         if (pageSize == null || pageSize < 1) pageSize = 20;
 
@@ -109,8 +109,8 @@ public class SeAlarmServiceImpl implements SeAlarmService {
 
     @Override
     public PageResult<SeAlarmListVO> queryVoltageAlarmList(String id, Integer type, String feederName,
-                                                            String startDate, String endDate, String orderDir,
-                                                            Integer page, Integer pageSize, String alarmLevel) {
+                                                           String startDate, String endDate, String orderDir,
+                                                           Integer page, Integer pageSize, String alarmLevel) {
         if (page == null || page < 1) page = 1;
         if (pageSize == null || pageSize < 1) pageSize = 20;
 
@@ -181,10 +181,15 @@ public class SeAlarmServiceImpl implements SeAlarmService {
             return buildOverloadDetail(currentEvent);
         }
 
-        // 电压事件(仅馈线级有详情,配变越限无详情)
+        // 电压事件
         FhzgSeVoltageEvent voltageEvent = voltageEventMapper.selectById(alarmEventId);
-        if (voltageEvent != null && "feeder".equals(voltageEvent.getAlarmLevel())) {
-            return buildFeederDetail(voltageEvent);
+        if (voltageEvent != null) {
+            if ("feeder".equals(voltageEvent.getAlarmLevel())) {
+                return buildFeederDetail(voltageEvent);
+            }
+            if ("mvtrans".equals(voltageEvent.getAlarmLevel())) {
+                return buildMvtransDetail(voltageEvent);
+            }
         }
 
         return null;
@@ -244,23 +249,44 @@ public class SeAlarmServiceImpl implements SeAlarmService {
                 .build();
     }
 
-//    /**
-//     * 单配变事件详情:展示该配变自身信息
-//     */
-//    private SeAlarmDetailVO buildMvtransDetail(FhzgSeVoltageEvent event) {
-//        LocalDateTime endTime = event.getRecoverTime() != null ? event.getRecoverTime()
-//                : (event.getTriggerTime() != null ? event.getTriggerTime() : event.getFirstOverTime());
-//        return SeAlarmDetailVO.builder()
-//                .alarmEventId(event.getId())
-//                .alarmType(event.getAlarmType())
-//                .alarmCategory("voltage")
-//                .countyName(event.getCountyName())
-//                .feederName(event.getFeederName())
-//                .alarmStartTime(event.getFirstOverTime())
-//                .alarmEndTime(endTime)
-//                .abnormalIndicator(resolveVoltageDisplay(event.getAlarmType(), event.getAlarmLevel()))
-//                .build();
-//    }
+    /**
+     * 配变事件详情:展示基础字段 + 事件窗口内电压 max/min
+     */
+    private SeAlarmDetailVO buildMvtransDetail(FhzgSeVoltageEvent event) {
+        LocalDateTime endTime = event.getRecoverTime() != null ? event.getRecoverTime()
+                : (event.getTriggerTime() != null ? event.getTriggerTime() : event.getFirstOverTime());
+
+        // 查询事件窗口内该配变的低压侧电压 max/min
+        BigDecimal maxVoltage = null, minVoltage = null;
+        if (event.getFirstOverTime() != null && event.getDeviceId() != null) {
+            List<FhzgSeSnapshotDetail> snaps = snapshotDetailMapper.selectList(
+                    new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
+                            .eq(FhzgSeSnapshotDetail::getDeviceId, event.getDeviceId())
+                            .eq(FhzgSeSnapshotDetail::getDeviceType, "mvtrans")
+                            .isNotNull(FhzgSeSnapshotDetail::getLvVoltageA)
+                            .ge(FhzgSeSnapshotDetail::getSnapshotTime, event.getFirstOverTime())
+                            .le(FhzgSeSnapshotDetail::getSnapshotTime, endTime));
+            for (FhzgSeSnapshotDetail s : snaps) {
+                BigDecimal v = s.getLvVoltageA();
+                if (v == null) continue;
+                if (maxVoltage == null || v.compareTo(maxVoltage) > 0) maxVoltage = v;
+                if (minVoltage == null || v.compareTo(minVoltage) < 0) minVoltage = v;
+            }
+        }
+
+        return SeAlarmDetailVO.builder()
+                .alarmEventId(event.getId())
+                .alarmType(event.getAlarmType())
+                .alarmCategory("voltage")
+                .countyName(event.getCountyName())
+                .feederName(event.getFeederName())
+                .alarmStartTime(event.getFirstOverTime())
+                .alarmEndTime(endTime)
+                .abnormalIndicator(resolveVoltageDisplay(event.getAlarmType(), event.getAlarmLevel()))
+                .maxVoltage(maxVoltage)
+                .minVoltage(minVoltage)
+                .build();
+    }
 
     private SeAlarmDetailVO buildOverloadDetail(FhzgSeCurrentEvent event) {
         LocalDateTime endTime = event.getRecoverTime();
@@ -379,7 +405,7 @@ public class SeAlarmServiceImpl implements SeAlarmService {
     }
 
     private <T> void applyOrderBy(LambdaQueryWrapper<T> wrapper, String orderDir,
-                                   com.baomidou.mybatisplus.core.toolkit.support.SFunction<T, ?> column) {
+                                  com.baomidou.mybatisplus.core.toolkit.support.SFunction<T, ?> column) {
         if ("asc".equalsIgnoreCase(orderDir)) {
             wrapper.orderByAsc(column);
         } else {
@@ -388,7 +414,7 @@ public class SeAlarmServiceImpl implements SeAlarmService {
     }
 
     private void collectFeeders(com.hdkj.fhzg.optimization.response.FeederGroupTreeNode node,
-                                 java.util.List<FeederSelectVO> result) {
+                                java.util.List<FeederSelectVO> result) {
         if (node.getType() == 4) {
             result.add(new FeederSelectVO(node.getId(), node.getName()));
         }
@@ -398,4 +424,4 @@ public class SeAlarmServiceImpl implements SeAlarmService {
             }
         }
     }
-}
+}

+ 77 - 56
services/load-transfer-bf/src/main/java/com/hdkj/lt/bf/service/impl/SeSnapshotServiceImpl.java

@@ -143,7 +143,7 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
     }
 
     private void processFeederCurrent(JSONObject f, FhzgSeSnapshotDetail detail,
-                                       LocalDateTime snapTime, Map<String, String[]> feederMap) {
+                                      LocalDateTime snapTime, Map<String, String[]> feederMap) {
         if (detail.getCurrentStatus() == null) return;
         String feederId = detail.getFeederId();
         String[] loc = feederMap.get(feederId);
@@ -194,10 +194,11 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
                     currentEventMapper.insert(event);
                     state.setAlarmTriggered(1);
                     state.setAlarmEventId(event.getId());
-                    // 异步触发重构算法(需要 feeder_id + point_time)
+                    // 取事件窗口内最大负载率断面时刻作为重构触发断面时刻
+                    LocalDateTime maxLrTime = findMaxLoadRateTime(feederId, state.getFirstOverTime(), snapTime);
                     eventPublisher.publishEvent(new ReconTriggerEvent(
                             event.getId(), feederId, feederName, countyId, subsId,
-                            alarmType, snapTime, state.getFirstOverTime()));
+                            alarmType, maxLrTime, state.getFirstOverTime()));
                 }
             } else {
                 if (state.getAlarmTriggered() == 1 && state.getAlarmEventId() != null) {
@@ -215,7 +216,7 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
     }
 
     private void processFeederVoltage(JSONObject f, FhzgSeSnapshotDetail detail,
-                                       LocalDateTime snapTime, Map<String, String[]> feederMap) {
+                                      LocalDateTime snapTime, Map<String, String[]> feederMap) {
         if (detail.getVoltageStatus() == null) return;
         String[] loc = feederMap.get(detail.getFeederId());
         checkVoltageMonitor(detail.getFeederId(), "feeder", detail.getVoltageRatio(), detail.getVoltageStatus(),
@@ -246,7 +247,7 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
     }
 
     private void processMvtransMonitor(JSONObject m, FhzgSeSnapshotDetail detail,
-                                        LocalDateTime snapTime, Map<String, String[]> feederMap) {
+                                       LocalDateTime snapTime, Map<String, String[]> feederMap) {
         if (detail.getVoltageStatus() == null) return;
         String mvtransId = detail.getDeviceId();
         String[] loc = feederMap.get(detail.getFeederId());
@@ -270,9 +271,9 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
     // ============================================================
 
     private void checkVoltageMonitor(String deviceId, String deviceType,
-                                      BigDecimal voltageRatio, int voltageStatus,
-                                      LocalDateTime snapTime, String feederId, String feederName,
-                                      String subsId, String countyId, String mvtransId, String consumerId) {
+                                     BigDecimal voltageRatio, int voltageStatus,
+                                     LocalDateTime snapTime, String feederId, String feederName,
+                                     String subsId, String countyId, String mvtransId, String consumerId) {
         FhzgSeMonitorVoltage state = monitorVoltageMapper.selectOne(
                 new LambdaQueryWrapper<FhzgSeMonitorVoltage>()
                         .eq(FhzgSeMonitorVoltage::getDeviceId, deviceId)
@@ -299,53 +300,53 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
                 if (state.getFirstOverTime() != null
                         && Duration.between(state.getFirstOverTime(), snapTime).toMinutes() >= SeMonitorThreshold.TRIGGER_DURATION_MINUTES
                         && state.getAlarmTriggered() == 0) {
-                            String countyName = lookupCountyName(countyId, null);
-
-                            if ("feeder".equals(deviceType)) {
-                                // === 馈线自身越限 → 创建 feeder 级独立事件 ===
-                                String alarmType = resolveVoltageAlarmType(deviceType, voltageStatus);
-                                BigDecimal threshold = resolveVoltageThreshold(deviceType, voltageStatus);
-                                BigDecimal[] vr = queryVoltageRangeFromSnap(feederId, state.getFirstOverTime(), snapTime);
-                                int[] mc = queryMvtransCounts(feederId, state.getFirstOverTime(), snapTime);
-                                FhzgSeVoltageEvent event = FhzgSeVoltageEvent.builder()
-                                        .deviceId(deviceId).deviceName(feederName)
-                                        .deviceType(deviceType).alarmLevel(deviceType).alarmType(alarmType)
-                                        .feederId(feederId).feederName(feederName)
-                                        .subsId(subsId).countyId(countyId).countyName(countyName)
-                                        .threshold(threshold)
-                                        .firstOverTime(state.getFirstOverTime()).triggerTime(snapTime)
-                                        .triggerValue(voltageRatio)
-                                        .voltageRangeMax(vr[0]).voltageRangeMin(vr[1])
-                                        .overUpperMvtrans(mc[0]).overLowerMvtrans(mc[1])
-                                        .lastValue(voltageRatio).status(1).build();
-                                voltageEventMapper.insert(event);
-                                state.setAlarmTriggered(1); state.setAlarmEventId(event.getId());
-                                // 馈线越下限 → 异步触发重构算法
-                                if ("feeder".equals(deviceType) && "voltage_under".equals(alarmType)) {
-                                    eventPublisher.publishEvent(new ReconTriggerEvent(
-                                            event.getId(), feederId, feederName, countyId, subsId,
-                                            alarmType, snapTime, state.getFirstOverTime()));
-                                }
-                            } else if ("mvtrans".equals(deviceType)) {
-                                // === 台区越限 → 创建 mvtrans 级独立事件 ===
-                                String alarmType = resolveVoltageAlarmType(deviceType, voltageStatus);
-                                BigDecimal threshold = resolveVoltageThreshold(deviceType, voltageStatus);
-                                FhzgSeVoltageEvent event = FhzgSeVoltageEvent.builder()
-                                        .deviceId(deviceId).deviceName(feederName)
-                                        .deviceType(deviceType).alarmLevel(deviceType).alarmType(alarmType)
-                                        .feederId(feederId).feederName(feederName)
-                                        .subsId(subsId).countyId(countyId).countyName(countyName)
-                                        .mvtransId(mvtransId)
-                                        .threshold(threshold)
-                                        .firstOverTime(state.getFirstOverTime()).triggerTime(snapTime)
-                                        .triggerValue(voltageRatio).lastValue(voltageRatio).status(1)
-                                        .build();
-                                voltageEventMapper.insert(event);
-                                state.setAlarmTriggered(1);
-                                state.setAlarmEventId(event.getId());
-                            }
-                            // consumer 级别暂走旧逻辑(如有可后续优化)
+                    String countyName = lookupCountyName(countyId, null);
+
+                    if ("feeder".equals(deviceType)) {
+                        // === 馈线自身越限 → 创建 feeder 级独立事件 ===
+                        String alarmType = resolveVoltageAlarmType(deviceType, voltageStatus);
+                        BigDecimal threshold = resolveVoltageThreshold(deviceType, voltageStatus);
+                        BigDecimal[] vr = queryVoltageRangeFromSnap(feederId, state.getFirstOverTime(), snapTime);
+                        int[] mc = queryMvtransCounts(feederId, state.getFirstOverTime(), snapTime);
+                        FhzgSeVoltageEvent event = FhzgSeVoltageEvent.builder()
+                                .deviceId(deviceId).deviceName(feederName)
+                                .deviceType(deviceType).alarmLevel(deviceType).alarmType(alarmType)
+                                .feederId(feederId).feederName(feederName)
+                                .subsId(subsId).countyId(countyId).countyName(countyName)
+                                .threshold(threshold)
+                                .firstOverTime(state.getFirstOverTime()).triggerTime(snapTime)
+                                .triggerValue(voltageRatio)
+                                .voltageRangeMax(vr[0]).voltageRangeMin(vr[1])
+                                .overUpperMvtrans(mc[0]).overLowerMvtrans(mc[1])
+                                .lastValue(voltageRatio).status(1).build();
+                        voltageEventMapper.insert(event);
+                        state.setAlarmTriggered(1); state.setAlarmEventId(event.getId());
+                        // 馈线越下限 → 异步触发重构算法
+                        if ("feeder".equals(deviceType) && "voltage_under".equals(alarmType)) {
+                            eventPublisher.publishEvent(new ReconTriggerEvent(
+                                    event.getId(), feederId, feederName, countyId, subsId,
+                                    alarmType, snapTime, state.getFirstOverTime()));
                         }
+                    } else if ("mvtrans".equals(deviceType)) {
+                        // === 台区越限 → 创建 mvtrans 级独立事件 ===
+                        String alarmType = resolveVoltageAlarmType(deviceType, voltageStatus);
+                        BigDecimal threshold = resolveVoltageThreshold(deviceType, voltageStatus);
+                        FhzgSeVoltageEvent event = FhzgSeVoltageEvent.builder()
+                                .deviceId(deviceId).deviceName(feederName)
+                                .deviceType(deviceType).alarmLevel(deviceType).alarmType(alarmType)
+                                .feederId(feederId).feederName(feederName)
+                                .subsId(subsId).countyId(countyId).countyName(countyName)
+                                .mvtransId(mvtransId)
+                                .threshold(threshold)
+                                .firstOverTime(state.getFirstOverTime()).triggerTime(snapTime)
+                                .triggerValue(voltageRatio).lastValue(voltageRatio).status(1)
+                                .build();
+                        voltageEventMapper.insert(event);
+                        state.setAlarmTriggered(1);
+                        state.setAlarmEventId(event.getId());
+                    }
+                    // consumer 级别暂走旧逻辑(如有可后续优化)
+                }
             } else {
                 if (state.getAlarmTriggered() == 1 && state.getAlarmEventId() != null) {
                     // 只有 feeder 自身恢复才标聚合事件 status=2;mvtrans 恢复不动聚合事件
@@ -501,6 +502,26 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
         try { return new BigDecimal(v); } catch (NumberFormatException e) { return null; }
     }
 
+    /**
+     * 查事件窗口 [start, end] 内该馈线最大负载率的那条断面的 snapshotTime
+     */
+    private LocalDateTime findMaxLoadRateTime(String feederId, LocalDateTime start, LocalDateTime end) {
+        if (feederId == null || start == null) return end;
+        List<FhzgSeSnapshotDetail> list = snapshotDetailMapper.selectList(
+                new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
+                        .eq(FhzgSeSnapshotDetail::getFeederId, feederId)
+                        .eq(FhzgSeSnapshotDetail::getDeviceType, "feeder")
+                        .isNotNull(FhzgSeSnapshotDetail::getLoadRate)
+                        .ge(FhzgSeSnapshotDetail::getSnapshotTime, start)
+                        .le(FhzgSeSnapshotDetail::getSnapshotTime, end != null ? end : LocalDateTime.now())
+                        .orderByDesc(FhzgSeSnapshotDetail::getLoadRate)
+                        .last("LIMIT 1"));
+        if (list != null && !list.isEmpty()) {
+            return list.get(0).getSnapshotTime();
+        }
+        return end;
+    }
+
     /**
      * 按 countyId 从 SeSnapshotConstants.COUNTIES 查 countyName。
      * COUNTIES 的 key=countyId(=maintOrg UUID),value=[countySid, countyName]
@@ -527,7 +548,7 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
     }
 
     private void buildFeederMappingRecursive(List<FeederGroupTreeNode> nodes, Map<String, String[]> map,
-                                              String parentSubsId, String parentCountyId) {
+                                             String parentSubsId, String parentCountyId) {
         if (nodes == null) return;
         for (FeederGroupTreeNode node : nodes) {
             String subsId = parentSubsId, countyId = parentCountyId;
@@ -562,4 +583,4 @@ public class SeSnapshotServiceImpl implements SeSnapshotService {
         // 重新走正常流程写入(此时防重逻辑不会跳过任何记录)
         processSnapshot(snapshotJson);
     }
-}
+}