|
|
@@ -3,6 +3,7 @@ package com.hdkj.lt.bf.service.impl;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
import com.hdkj.lt.bf.application.FeederGroupApplication;
|
|
|
+import com.hdkj.lt.bf.entity.FhzgSeCurrentEvent;
|
|
|
import com.hdkj.lt.bf.entity.FhzgDwmVoltageOverLimitDaily;
|
|
|
import com.hdkj.lt.bf.entity.FhzgSeCapacityDaily;
|
|
|
import com.hdkj.lt.bf.entity.FhzgSeVoltageEvent;
|
|
|
@@ -11,6 +12,7 @@ import com.hdkj.lt.bf.entity.dto.TodayOutageData;
|
|
|
import com.hdkj.lt.bf.entity.vo.SeCapacityDashboardVO;
|
|
|
import com.hdkj.lt.bf.entity.vo.SeOutageDashboardVO;
|
|
|
import com.hdkj.lt.bf.entity.vo.SeVoltageDashboardVO;
|
|
|
+import com.hdkj.lt.bf.mapper.FhzgSeCurrentEventMapper;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgDwmVoltageOverLimitDailyMapper;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgSeCapacityDailyMapper;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgSeVoltageEventMapper;
|
|
|
@@ -47,6 +49,7 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
private final FhzgDwmVoltageOverLimitDailyMapper voltageDailyMapper;
|
|
|
private final FhzgSeSnapshotDetailMapper snapshotDetailMapper;
|
|
|
private final FhzgSeCapacityDailyMapper capacityDailyMapper;
|
|
|
+ private final FhzgSeCurrentEventMapper currentEventMapper;
|
|
|
private final FeederGroupApplication feederGroupApplication;
|
|
|
|
|
|
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
@@ -97,17 +100,47 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 今日电压:COUNT 聚合到 SQL,按 alarmLevel + alarmType 分组
|
|
|
- * 返回4个计数:台区越上限/下限 + 馈线越上限/下限
|
|
|
+ * 今日电压:线路越限数从 feeder 事件 (alarm_level='feeder') 统计,
|
|
|
+ * 台区越限数从 mvtrans 事件 (alarm_level='mvtrans') 直接 COUNT。
|
|
|
+ * 按 firstOverTime 今日范围 + status=1(活跃)过滤。
|
|
|
*/
|
|
|
private SeVoltageDashboardVO queryVoltageToday(String id, Integer type) {
|
|
|
LocalDateTime todayStart = LocalDate.now().atStartOfDay();
|
|
|
- LocalDateTime now = LocalDateTime.now();
|
|
|
+ LocalDateTime tomorrowStart = LocalDate.now().plusDays(1).atStartOfDay();
|
|
|
+
|
|
|
+ // == 线路越限事件统计(alarm_level='feeder')==
|
|
|
+ LambdaQueryWrapper<FhzgSeVoltageEvent> feederWrapper = new LambdaQueryWrapper<FhzgSeVoltageEvent>()
|
|
|
+ .eq(FhzgSeVoltageEvent::getAlarmLevel, "feeder")
|
|
|
+ .ge(FhzgSeVoltageEvent::getFirstOverTime, todayStart)
|
|
|
+ .lt(FhzgSeVoltageEvent::getFirstOverTime, tomorrowStart)
|
|
|
+ .eq(FhzgSeVoltageEvent::getStatus, 1);
|
|
|
+ applyNodeFilter(feederWrapper, id, type);
|
|
|
+ List<FhzgSeVoltageEvent> feederEvents = voltageEventMapper.selectList(feederWrapper);
|
|
|
+
|
|
|
+ int overUpperFeeder = 0, overLowerFeeder = 0;
|
|
|
+ for (FhzgSeVoltageEvent e : feederEvents) {
|
|
|
+ String t = e.getAlarmType();
|
|
|
+ if (t == null) continue;
|
|
|
+ if (t.contains("over")) overUpperFeeder++;
|
|
|
+ if (t.contains("under")) overLowerFeeder++;
|
|
|
+ }
|
|
|
|
|
|
- int overUpperArea = countVoltageEvents(id, type, todayStart, now, "mvtrans", "over");
|
|
|
- int overLowerArea = countVoltageEvents(id, type, todayStart, now, "mvtrans", "under");
|
|
|
- int overUpperFeeder = countVoltageEvents(id, type, todayStart, now, "feeder", "over");
|
|
|
- int overLowerFeeder = countVoltageEvents(id, type, todayStart, now, "feeder", "under");
|
|
|
+ // == 配变越限事件统计(alarm_level='mvtrans')==
|
|
|
+ LambdaQueryWrapper<FhzgSeVoltageEvent> mvtransWrapper = new LambdaQueryWrapper<FhzgSeVoltageEvent>()
|
|
|
+ .eq(FhzgSeVoltageEvent::getAlarmLevel, "mvtrans")
|
|
|
+ .ge(FhzgSeVoltageEvent::getFirstOverTime, todayStart)
|
|
|
+ .lt(FhzgSeVoltageEvent::getFirstOverTime, tomorrowStart)
|
|
|
+ .eq(FhzgSeVoltageEvent::getStatus, 1);
|
|
|
+ applyNodeFilter(mvtransWrapper, id, type);
|
|
|
+ List<FhzgSeVoltageEvent> mvtransEvents = voltageEventMapper.selectList(mvtransWrapper);
|
|
|
+
|
|
|
+ int overUpperArea = 0, overLowerArea = 0;
|
|
|
+ for (FhzgSeVoltageEvent e : mvtransEvents) {
|
|
|
+ String t = e.getAlarmType();
|
|
|
+ if (t == null) continue;
|
|
|
+ if (t.contains("over")) overUpperArea++;
|
|
|
+ if (t.contains("under")) overLowerArea++;
|
|
|
+ }
|
|
|
|
|
|
return SeVoltageDashboardVO.builder()
|
|
|
.todayOverUpperAreaCount(overUpperArea)
|
|
|
@@ -118,20 +151,30 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 按节点+时段+类型统计电压越限事件数
|
|
|
+ * 按节点+时段统计重过载事件数
|
|
|
+ * 返回 int[2]: [0]=重载事件数, [1]=过载事件数
|
|
|
*/
|
|
|
- private int countVoltageEvents(String id, Integer type,
|
|
|
- LocalDateTime start, LocalDateTime end,
|
|
|
- String alarmLevel, String overOrUnder) {
|
|
|
- LambdaQueryWrapper<FhzgSeVoltageEvent> wrapper = new LambdaQueryWrapper<FhzgSeVoltageEvent>()
|
|
|
- .ge(FhzgSeVoltageEvent::getTriggerTime, start)
|
|
|
- .le(FhzgSeVoltageEvent::getTriggerTime, end)
|
|
|
- .eq(FhzgSeVoltageEvent::getStatus, 1)
|
|
|
- .eq(FhzgSeVoltageEvent::getAlarmLevel, alarmLevel)
|
|
|
- .like(FhzgSeVoltageEvent::getAlarmType, overOrUnder);
|
|
|
- applyNodeFilter(wrapper, id, type);
|
|
|
- Long count = voltageEventMapper.selectCount(wrapper);
|
|
|
- return count != null ? count.intValue() : 0;
|
|
|
+ private int[] countCurrentEvents(String id, Integer type,
|
|
|
+ LocalDateTime start, LocalDateTime end) {
|
|
|
+ LambdaQueryWrapper<FhzgSeCurrentEvent> wrapper = new LambdaQueryWrapper<FhzgSeCurrentEvent>()
|
|
|
+ .ge(FhzgSeCurrentEvent::getFirstOverTime, start)
|
|
|
+ .lt(FhzgSeCurrentEvent::getFirstOverTime, end)
|
|
|
+ .in(FhzgSeCurrentEvent::getAlarmType, "current_heavy", "current_overload");
|
|
|
+ if (type == 2) {
|
|
|
+ wrapper.eq(FhzgSeCurrentEvent::getCountyId, id);
|
|
|
+ } else if (type == 3) {
|
|
|
+ wrapper.eq(FhzgSeCurrentEvent::getSubsId, id);
|
|
|
+ } else if (type == 4) {
|
|
|
+ wrapper.eq(FhzgSeCurrentEvent::getFeederId, id);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<FhzgSeCurrentEvent> events = currentEventMapper.selectList(wrapper);
|
|
|
+ int heavy = 0, overload = 0;
|
|
|
+ for (FhzgSeCurrentEvent e : events) {
|
|
|
+ if ("current_heavy".equals(e.getAlarmType())) heavy++;
|
|
|
+ else if ("current_overload".equals(e.getAlarmType())) overload++;
|
|
|
+ }
|
|
|
+ return new int[]{heavy, overload};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -280,40 +323,54 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 今日供电能力:实时查 snapshot_detail(量小,一个馈线一天最多96行)
|
|
|
- * 馈线级别附加96点时序(负载率+电流+电压+有功+无功)
|
|
|
+ * 今日供电能力:负载率从断面明细聚合,重过载次数从事件表统计
|
|
|
*/
|
|
|
private SeCapacityDashboardVO queryCapacityToday(String id, Integer type) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
LocalDateTime startTime = today.atStartOfDay();
|
|
|
LocalDateTime endTime = LocalDateTime.now();
|
|
|
|
|
|
- LambdaQueryWrapper<FhzgSeSnapshotDetail> wrapper = new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
|
|
|
+ // 1. 负载率:从断面明细聚合(保持馈线96点时序)
|
|
|
+ LambdaQueryWrapper<FhzgSeSnapshotDetail> snapshotWrapper = new LambdaQueryWrapper<FhzgSeSnapshotDetail>()
|
|
|
.eq(FhzgSeSnapshotDetail::getDeviceType, "feeder")
|
|
|
.isNotNull(FhzgSeSnapshotDetail::getLoadRate)
|
|
|
.ge(FhzgSeSnapshotDetail::getSnapshotTime, startTime)
|
|
|
.le(FhzgSeSnapshotDetail::getSnapshotTime, endTime);
|
|
|
+ applySnapshotFilter(snapshotWrapper, id, type);
|
|
|
+ List<FhzgSeSnapshotDetail> snapshots = snapshotDetailMapper.selectList(snapshotWrapper);
|
|
|
|
|
|
- applySnapshotFilter(wrapper, id, type);
|
|
|
-
|
|
|
- List<FhzgSeSnapshotDetail> snapshots = snapshotDetailMapper.selectList(wrapper);
|
|
|
-
|
|
|
+ SeCapacityDashboardVO vo;
|
|
|
if (snapshots.isEmpty()) {
|
|
|
- return SeCapacityDashboardVO.builder().build();
|
|
|
+ vo = SeCapacityDashboardVO.builder().build();
|
|
|
+ } else {
|
|
|
+ vo = aggregateSnapshots(snapshots);
|
|
|
+ // 馈线 → 附加96点时序
|
|
|
+ if (type == 4) {
|
|
|
+ vo.setLoadRateSeries(buildFeederTimeSeries(snapshots));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- SeCapacityDashboardVO vo = aggregateSnapshots(snapshots);
|
|
|
-
|
|
|
- // 馈线 → 附加96点时序
|
|
|
- if (type == 4) {
|
|
|
- vo.setLoadRateSeries(buildFeederTimeSeries(snapshots));
|
|
|
+ // 2. 重过载事件次数:从事件表统计
|
|
|
+ int[] eventCounts = countCurrentEvents(id, type, startTime, endTime);
|
|
|
+ vo.setHeavyLoadEventCount(eventCounts[0]);
|
|
|
+ vo.setOverloadEventCount(eventCounts[1]);
|
|
|
+ int totalEvents = eventCounts[0] + eventCounts[1];
|
|
|
+ vo.setTotalEventCount(totalEvents);
|
|
|
+ if (totalEvents > 0) {
|
|
|
+ vo.setHeavyLoadRate(new BigDecimal(eventCounts[0] * 100)
|
|
|
+ .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
+ vo.setOverloadRate(new BigDecimal(eventCounts[1] * 100)
|
|
|
+ .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
+ } else {
|
|
|
+ vo.setHeavyLoadRate(BigDecimal.ZERO);
|
|
|
+ vo.setOverloadRate(BigDecimal.ZERO);
|
|
|
}
|
|
|
return vo;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 历史供电能力:查 capacity_daily 日汇总表(每馈线每天一行,量极小)
|
|
|
- * month = 月初~昨天;year = 1.1~昨天
|
|
|
+ * 历史供电能力:负载率从日汇总表查,重过载次数从事件表统计
|
|
|
+ * month = 月初 ~ 昨天;year = 1.1 ~ 昨天
|
|
|
*/
|
|
|
private SeCapacityDashboardVO queryCapacityHistory(String id, Integer type, String timeScope) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
@@ -331,55 +388,54 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
return SeCapacityDashboardVO.builder().build();
|
|
|
}
|
|
|
|
|
|
+ // 1. 负载率:从日汇总表聚合
|
|
|
LambdaQueryWrapper<FhzgSeCapacityDaily> wrapper = new LambdaQueryWrapper<FhzgSeCapacityDaily>()
|
|
|
.ge(FhzgSeCapacityDaily::getStatDate, startDate)
|
|
|
.le(FhzgSeCapacityDaily::getStatDate, endDate);
|
|
|
-
|
|
|
applyCapacityDailyFilter(wrapper, id, type);
|
|
|
-
|
|
|
List<FhzgSeCapacityDaily> dailyRecords = capacityDailyMapper.selectList(wrapper);
|
|
|
|
|
|
+ SeCapacityDashboardVO vo;
|
|
|
if (dailyRecords.isEmpty()) {
|
|
|
- return SeCapacityDashboardVO.builder().build();
|
|
|
- }
|
|
|
-
|
|
|
- // 聚合日汇总
|
|
|
- BigDecimal maxLoadRate = BigDecimal.ZERO;
|
|
|
- BigDecimal sumAvg = BigDecimal.ZERO;
|
|
|
- int totalHeavy = 0, totalOverload = 0, totalSnapshots = 0;
|
|
|
- for (FhzgSeCapacityDaily d : dailyRecords) {
|
|
|
- if (d.getMaxLoadRate() != null && d.getMaxLoadRate().compareTo(maxLoadRate) > 0) {
|
|
|
- maxLoadRate = d.getMaxLoadRate();
|
|
|
- }
|
|
|
- if (d.getAvgLoadRate() != null) {
|
|
|
- sumAvg = sumAvg.add(d.getAvgLoadRate());
|
|
|
+ vo = SeCapacityDashboardVO.builder().build();
|
|
|
+ } else {
|
|
|
+ BigDecimal maxLoadRate = BigDecimal.ZERO;
|
|
|
+ BigDecimal sumAvg = BigDecimal.ZERO;
|
|
|
+ for (FhzgSeCapacityDaily d : dailyRecords) {
|
|
|
+ if (d.getMaxLoadRate() != null && d.getMaxLoadRate().compareTo(maxLoadRate) > 0) {
|
|
|
+ maxLoadRate = d.getMaxLoadRate();
|
|
|
+ }
|
|
|
+ if (d.getAvgLoadRate() != null) {
|
|
|
+ sumAvg = sumAvg.add(d.getAvgLoadRate());
|
|
|
+ }
|
|
|
}
|
|
|
- totalHeavy += d.getHeavyCount() != null ? d.getHeavyCount() : 0;
|
|
|
- totalOverload += d.getOverloadCount() != null ? d.getOverloadCount() : 0;
|
|
|
- totalSnapshots += d.getTotalSnapshots() != null ? d.getTotalSnapshots() : 0;
|
|
|
+ BigDecimal avgLoadRate = !dailyRecords.isEmpty()
|
|
|
+ ? sumAvg.divide(BigDecimal.valueOf(dailyRecords.size()), 2, RoundingMode.HALF_UP)
|
|
|
+ : BigDecimal.ZERO;
|
|
|
+ vo = SeCapacityDashboardVO.builder()
|
|
|
+ .maxLoadRate(maxLoadRate)
|
|
|
+ .avgLoadRate(avgLoadRate)
|
|
|
+ .build();
|
|
|
}
|
|
|
|
|
|
- int totalEvents = totalHeavy + totalOverload;
|
|
|
- int recordCount = dailyRecords.size();
|
|
|
- BigDecimal avgLoadRate = recordCount > 0
|
|
|
- ? sumAvg.divide(BigDecimal.valueOf(recordCount), 2, RoundingMode.HALF_UP)
|
|
|
- : BigDecimal.ZERO;
|
|
|
- BigDecimal heavyRate = totalSnapshots > 0
|
|
|
- ? BigDecimal.valueOf(totalHeavy * 100).divide(BigDecimal.valueOf(totalSnapshots), 2, RoundingMode.HALF_UP)
|
|
|
- : BigDecimal.ZERO;
|
|
|
- BigDecimal overloadRate = totalSnapshots > 0
|
|
|
- ? BigDecimal.valueOf(totalOverload * 100).divide(BigDecimal.valueOf(totalSnapshots), 2, RoundingMode.HALF_UP)
|
|
|
- : BigDecimal.ZERO;
|
|
|
-
|
|
|
- return SeCapacityDashboardVO.builder()
|
|
|
- .maxLoadRate(maxLoadRate)
|
|
|
- .avgLoadRate(avgLoadRate)
|
|
|
- .heavyLoadEventCount(totalHeavy)
|
|
|
- .overloadEventCount(totalOverload)
|
|
|
- .heavyLoadRate(heavyRate)
|
|
|
- .overloadRate(overloadRate)
|
|
|
- .totalEventCount(totalEvents)
|
|
|
- .build();
|
|
|
+ // 2. 重过载事件次数:从事件表统计
|
|
|
+ LocalDateTime rangeStart = startDate.atStartOfDay();
|
|
|
+ LocalDateTime rangeEnd = endDate.atTime(23, 59, 59);
|
|
|
+ int[] eventCounts = countCurrentEvents(id, type, rangeStart, rangeEnd);
|
|
|
+ vo.setHeavyLoadEventCount(eventCounts[0]);
|
|
|
+ vo.setOverloadEventCount(eventCounts[1]);
|
|
|
+ int totalEvents = eventCounts[0] + eventCounts[1];
|
|
|
+ vo.setTotalEventCount(totalEvents);
|
|
|
+ if (totalEvents > 0) {
|
|
|
+ vo.setHeavyLoadRate(new BigDecimal(eventCounts[0] * 100)
|
|
|
+ .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
+ vo.setOverloadRate(new BigDecimal(eventCounts[1] * 100)
|
|
|
+ .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
+ } else {
|
|
|
+ vo.setHeavyLoadRate(BigDecimal.ZERO);
|
|
|
+ vo.setOverloadRate(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ return vo;
|
|
|
}
|
|
|
|
|
|
/**
|