|
|
@@ -4,6 +4,8 @@ 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.FhzgSeLineLossDaily;
|
|
|
+import com.hdkj.lt.bf.entity.FhzgSeLineLossDetail;
|
|
|
import com.hdkj.lt.bf.entity.FhzgDwmVoltageOverLimitDaily;
|
|
|
import com.hdkj.lt.bf.entity.FhzgSeCapacityDaily;
|
|
|
import com.hdkj.lt.bf.entity.FhzgSeVoltageEvent;
|
|
|
@@ -16,6 +18,8 @@ import com.hdkj.lt.bf.entity.vo.SeOutageDashboardVO;
|
|
|
import com.hdkj.lt.bf.entity.vo.SeVoltageDashboardVO;
|
|
|
import com.hdkj.lt.bf.entity.vo.SeVoltageIndexVO;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgSeCurrentEventMapper;
|
|
|
+import com.hdkj.lt.bf.mapper.FhzgSeLineLossDailyMapper;
|
|
|
+import com.hdkj.lt.bf.mapper.FhzgSeLineLossDetailMapper;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgDwmVoltageOverLimitDailyMapper;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgSeCapacityDailyMapper;
|
|
|
import com.hdkj.lt.bf.mapper.FhzgSeVoltageEventMapper;
|
|
|
@@ -58,6 +62,8 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
private final FhzgSeCurrentEventMapper currentEventMapper;
|
|
|
private final FhzgSeConsumerCountDailyMapper consumerCountDailyMapper;
|
|
|
private final FhzgSeConsumerRelationMapper consumerRelationMapper;
|
|
|
+ private final FhzgSeLineLossDetailMapper lineLossDetailMapper;
|
|
|
+ private final FhzgSeLineLossDailyMapper lineLossDailyMapper;
|
|
|
private final FeederGroupApplication feederGroupApplication;
|
|
|
|
|
|
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
@@ -103,11 +109,21 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ SeVoltageDashboardVO vo;
|
|
|
if ("today".equalsIgnoreCase(timeScope)) {
|
|
|
- return queryVoltageToday(id, type);
|
|
|
+ vo = queryVoltageToday(id, type);
|
|
|
} else {
|
|
|
- return queryVoltageHistory(id, type, timeScope);
|
|
|
+ vo = queryVoltageHistory(id, type, timeScope);
|
|
|
}
|
|
|
+
|
|
|
+ // IEC 用户电压指数:与 timeScope 一致(today→day, month/year 同名)
|
|
|
+ String indexScope = "today".equalsIgnoreCase(timeScope) ? "day" : timeScope;
|
|
|
+ SeVoltageIndexVO indexVo = queryVoltageIndex(id, type, indexScope);
|
|
|
+ if (indexVo != null) {
|
|
|
+ vo.setIecIndex(indexVo.getVoltageIndex());
|
|
|
+ }
|
|
|
+
|
|
|
+ return vo;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -206,7 +222,6 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
*/
|
|
|
private SeVoltageDashboardVO queryVoltageHistory(String id, Integer type, String timeScope) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
- LocalDate endDate;
|
|
|
LocalDate startDate;
|
|
|
|
|
|
if ("month".equalsIgnoreCase(timeScope)) {
|
|
|
@@ -217,86 +232,95 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
|
|
|
String dimLevel = resolveDimLevel(type);
|
|
|
|
|
|
- // 查中台日汇总表最新日期,判断是否需要补昨日
|
|
|
+ // 中台覆盖到哪天(T-2,动态自适应);无数据时 midEnd < startDate → 中台贡献为 0
|
|
|
String maxOverDate = queryDailyMaxOverDate(dimLevel, id, type);
|
|
|
- String yesterdayStr = today.minusDays(1).format(DATE_FMT);
|
|
|
- boolean needFillYesterday = (maxOverDate == null || maxOverDate.compareTo(yesterdayStr) < 0);
|
|
|
-
|
|
|
- if (needFillYesterday) {
|
|
|
- endDate = today.minusDays(2); // 中台只到T-2,补昨日T-1
|
|
|
- } else {
|
|
|
- endDate = today.minusDays(1); // 中台已有昨天
|
|
|
- }
|
|
|
-
|
|
|
- // 如果 endDate < startDate,返回空
|
|
|
- if (endDate.isBefore(startDate)) {
|
|
|
- return SeVoltageDashboardVO.builder().build();
|
|
|
+ LocalDate midEnd = startDate.minusDays(1);
|
|
|
+ if (maxOverDate != null) {
|
|
|
+ try {
|
|
|
+ LocalDate mo = LocalDate.parse(maxOverDate, DATE_FMT);
|
|
|
+ midEnd = mo.isAfter(today) ? today : mo;
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.warn("中台 over_date 解析失败: {}, 忽略中台贡献", maxOverDate);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- // 一条 SQL 聚合 16个count字段 + total_over_limit_hours
|
|
|
- QueryWrapper<FhzgDwmVoltageOverLimitDaily> qw = new QueryWrapper<>();
|
|
|
- qw.select(
|
|
|
- "COALESCE(SUM(over_upper_severe_tg_count),0) AS over_upper_severe_tg_count",
|
|
|
- "COALESCE(SUM(over_upper_severe_cust_count),0) AS over_upper_severe_cust_count",
|
|
|
- "COALESCE(SUM(over_upper_severe_feeder_count),0) AS over_upper_severe_feeder_count",
|
|
|
- "COALESCE(SUM(over_upper_severe_generatrix_count),0) AS over_upper_severe_generatrix_count",
|
|
|
- "COALESCE(SUM(over_upper_mild_tg_count),0) AS over_upper_mild_tg_count",
|
|
|
- "COALESCE(SUM(over_upper_mild_cust_count),0) AS over_upper_mild_cust_count",
|
|
|
- "COALESCE(SUM(over_upper_mild_feeder_count),0) AS over_upper_mild_feeder_count",
|
|
|
- "COALESCE(SUM(over_upper_mild_generatrix_count),0) AS over_upper_mild_generatrix_count",
|
|
|
- "COALESCE(SUM(over_lower_severe_tg_count),0) AS over_lower_severe_tg_count",
|
|
|
- "COALESCE(SUM(over_lower_severe_cust_count),0) AS over_lower_severe_cust_count",
|
|
|
- "COALESCE(SUM(over_lower_severe_feeder_count),0) AS over_lower_severe_feeder_count",
|
|
|
- "COALESCE(SUM(over_lower_severe_generatrix_count),0) AS over_lower_severe_generatrix_count",
|
|
|
- "COALESCE(SUM(over_lower_mild_tg_count),0) AS over_lower_mild_tg_count",
|
|
|
- "COALESCE(SUM(over_lower_mild_cust_count),0) AS over_lower_mild_cust_count",
|
|
|
- "COALESCE(SUM(over_lower_mild_feeder_count),0) AS over_lower_mild_feeder_count",
|
|
|
- "COALESCE(SUM(over_lower_mild_generatrix_count),0) AS over_lower_mild_generatrix_count",
|
|
|
- "COALESCE(SUM(total_over_limit_hours),0) AS total_over_limit_hours")
|
|
|
- .eq("dim_level", dimLevel)
|
|
|
- .ge("over_date", startDate.format(DATE_FMT))
|
|
|
- .le("over_date", endDate.format(DATE_FMT));
|
|
|
-
|
|
|
- // 维度过滤
|
|
|
- if (type == 2) {
|
|
|
- qw.eq("maintainer_id", id);
|
|
|
- } else if (type == 3) {
|
|
|
- qw.eq("substation_id", id);
|
|
|
- } else if (type == 4) {
|
|
|
- qw.eq("feeder_id", id);
|
|
|
- }
|
|
|
+ int overUpperSevereTg = 0, overUpperSevereCust = 0, overUpperSevereFeeder = 0, overUpperSevereGen = 0;
|
|
|
+ int overUpperMildTg = 0, overUpperMildCust = 0, overUpperMildFeeder = 0, overUpperMildGen = 0;
|
|
|
+ int overLowerSevereTg = 0, overLowerSevereCust = 0, overLowerSevereFeeder = 0, overLowerSevereGen = 0;
|
|
|
+ int overLowerMildTg = 0, overLowerMildCust = 0, overLowerMildFeeder = 0, overLowerMildGen = 0;
|
|
|
+ BigDecimal totalHours = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ // ===== 1. 中台贡献区间 [startDate, midEnd](T-2 滞后,月初/年初可能为空)=====
|
|
|
+ if (!midEnd.isBefore(startDate)) {
|
|
|
+ // 一条 SQL 聚合 16个count字段 + total_over_limit_hours
|
|
|
+ QueryWrapper<FhzgDwmVoltageOverLimitDaily> qw = new QueryWrapper<>();
|
|
|
+ qw.select(
|
|
|
+ "COALESCE(SUM(over_upper_severe_tg_count),0) AS over_upper_severe_tg_count",
|
|
|
+ "COALESCE(SUM(over_upper_severe_cust_count),0) AS over_upper_severe_cust_count",
|
|
|
+ "COALESCE(SUM(over_upper_severe_feeder_count),0) AS over_upper_severe_feeder_count",
|
|
|
+ "COALESCE(SUM(over_upper_severe_generatrix_count),0) AS over_upper_severe_generatrix_count",
|
|
|
+ "COALESCE(SUM(over_upper_mild_tg_count),0) AS over_upper_mild_tg_count",
|
|
|
+ "COALESCE(SUM(over_upper_mild_cust_count),0) AS over_upper_mild_cust_count",
|
|
|
+ "COALESCE(SUM(over_upper_mild_feeder_count),0) AS over_upper_mild_feeder_count",
|
|
|
+ "COALESCE(SUM(over_upper_mild_generatrix_count),0) AS over_upper_mild_generatrix_count",
|
|
|
+ "COALESCE(SUM(over_lower_severe_tg_count),0) AS over_lower_severe_tg_count",
|
|
|
+ "COALESCE(SUM(over_lower_severe_cust_count),0) AS over_lower_severe_cust_count",
|
|
|
+ "COALESCE(SUM(over_lower_severe_feeder_count),0) AS over_lower_severe_feeder_count",
|
|
|
+ "COALESCE(SUM(over_lower_severe_generatrix_count),0) AS over_lower_severe_generatrix_count",
|
|
|
+ "COALESCE(SUM(over_lower_mild_tg_count),0) AS over_lower_mild_tg_count",
|
|
|
+ "COALESCE(SUM(over_lower_mild_cust_count),0) AS over_lower_mild_cust_count",
|
|
|
+ "COALESCE(SUM(over_lower_mild_feeder_count),0) AS over_lower_mild_feeder_count",
|
|
|
+ "COALESCE(SUM(over_lower_mild_generatrix_count),0) AS over_lower_mild_generatrix_count",
|
|
|
+ "COALESCE(SUM(total_over_limit_hours),0) AS total_over_limit_hours")
|
|
|
+ .eq("dim_level", dimLevel)
|
|
|
+ .ge("over_date", startDate.format(DATE_FMT))
|
|
|
+ .le("over_date", midEnd.format(DATE_FMT));
|
|
|
+
|
|
|
+ // 维度过滤
|
|
|
+ if (type == 2) {
|
|
|
+ qw.eq("maintainer_id", id);
|
|
|
+ } else if (type == 3) {
|
|
|
+ qw.eq("substation_id", id);
|
|
|
+ } else if (type == 4) {
|
|
|
+ qw.eq("feeder_id", id);
|
|
|
+ }
|
|
|
|
|
|
- List<FhzgDwmVoltageOverLimitDaily> records = voltageDailyMapper.selectList(qw);
|
|
|
- FhzgDwmVoltageOverLimitDaily r = (records != null && !records.isEmpty()) ? records.get(0) : null;
|
|
|
-
|
|
|
- int overUpperSevereTg = r != null ? safeInt(r.getOverUpperSevereTgCount()) : 0;
|
|
|
- int overUpperSevereCust = r != null ? safeInt(r.getOverUpperSevereCustCount()) : 0;
|
|
|
- int overUpperSevereFeeder = r != null ? safeInt(r.getOverUpperSevereFeederCount()) : 0;
|
|
|
- int overUpperSevereGen = r != null ? safeInt(r.getOverUpperSevereGeneratrixCount()) : 0;
|
|
|
- int overUpperMildTg = r != null ? safeInt(r.getOverUpperMildTgCount()) : 0;
|
|
|
- int overUpperMildCust = r != null ? safeInt(r.getOverUpperMildCustCount()) : 0;
|
|
|
- int overUpperMildFeeder = r != null ? safeInt(r.getOverUpperMildFeederCount()) : 0;
|
|
|
- int overUpperMildGen = r != null ? safeInt(r.getOverUpperMildGeneratrixCount()) : 0;
|
|
|
- int overLowerSevereTg = r != null ? safeInt(r.getOverLowerSevereTgCount()) : 0;
|
|
|
- int overLowerSevereCust = r != null ? safeInt(r.getOverLowerSevereCustCount()) : 0;
|
|
|
- int overLowerSevereFeeder = r != null ? safeInt(r.getOverLowerSevereFeederCount()) : 0;
|
|
|
- int overLowerSevereGen = r != null ? safeInt(r.getOverLowerSevereGeneratrixCount()) : 0;
|
|
|
- int overLowerMildTg = r != null ? safeInt(r.getOverLowerMildTgCount()) : 0;
|
|
|
- int overLowerMildCust = r != null ? safeInt(r.getOverLowerMildCustCount()) : 0;
|
|
|
- int overLowerMildFeeder = r != null ? safeInt(r.getOverLowerMildFeederCount()) : 0;
|
|
|
- int overLowerMildGen = r != null ? safeInt(r.getOverLowerMildGeneratrixCount()) : 0;
|
|
|
- BigDecimal totalHours = r != null && r.getTotalOverLimitHours() != null
|
|
|
- ? r.getTotalOverLimitHours() : BigDecimal.ZERO;
|
|
|
-
|
|
|
- // 补昨日:中台无昨日数据时,从事件表SQL聚合,按 alarm_level 分流
|
|
|
- if (needFillYesterday) {
|
|
|
- LocalDateTime yesterdayStart = today.minusDays(1).atStartOfDay();
|
|
|
- LocalDateTime yesterdayEnd = today.minusDays(1).atTime(23, 59, 59);
|
|
|
+ List<FhzgDwmVoltageOverLimitDaily> records = voltageDailyMapper.selectList(qw);
|
|
|
+ FhzgDwmVoltageOverLimitDaily r = (records != null && !records.isEmpty()) ? records.get(0) : null;
|
|
|
+
|
|
|
+ overUpperSevereTg = r != null ? safeInt(r.getOverUpperSevereTgCount()) : 0;
|
|
|
+ overUpperSevereCust = r != null ? safeInt(r.getOverUpperSevereCustCount()) : 0;
|
|
|
+ overUpperSevereFeeder = r != null ? safeInt(r.getOverUpperSevereFeederCount()) : 0;
|
|
|
+ overUpperSevereGen = r != null ? safeInt(r.getOverUpperSevereGeneratrixCount()) : 0;
|
|
|
+ overUpperMildTg = r != null ? safeInt(r.getOverUpperMildTgCount()) : 0;
|
|
|
+ overUpperMildCust = r != null ? safeInt(r.getOverUpperMildCustCount()) : 0;
|
|
|
+ overUpperMildFeeder = r != null ? safeInt(r.getOverUpperMildFeederCount()) : 0;
|
|
|
+ overUpperMildGen = r != null ? safeInt(r.getOverUpperMildGeneratrixCount()) : 0;
|
|
|
+ overLowerSevereTg = r != null ? safeInt(r.getOverLowerSevereTgCount()) : 0;
|
|
|
+ overLowerSevereCust = r != null ? safeInt(r.getOverLowerSevereCustCount()) : 0;
|
|
|
+ overLowerSevereFeeder = r != null ? safeInt(r.getOverLowerSevereFeederCount()) : 0;
|
|
|
+ overLowerSevereGen = r != null ? safeInt(r.getOverLowerSevereGeneratrixCount()) : 0;
|
|
|
+ overLowerMildTg = r != null ? safeInt(r.getOverLowerMildTgCount()) : 0;
|
|
|
+ overLowerMildCust = r != null ? safeInt(r.getOverLowerMildCustCount()) : 0;
|
|
|
+ overLowerMildFeeder = r != null ? safeInt(r.getOverLowerMildFeederCount()) : 0;
|
|
|
+ overLowerMildGen = r != null ? safeInt(r.getOverLowerMildGeneratrixCount()) : 0;
|
|
|
+ totalHours = r != null && r.getTotalOverLimitHours() != null
|
|
|
+ ? r.getTotalOverLimitHours() : BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ===== 2. 事件表补差区间 [max(midEnd+1, startDate), today](跨月/跨年不越界)=====
|
|
|
+ LocalDate fillStart = midEnd.plusDays(1);
|
|
|
+ if (fillStart.isBefore(startDate)) {
|
|
|
+ fillStart = startDate;
|
|
|
+ }
|
|
|
+ if (!fillStart.isAfter(today)) {
|
|
|
+ LocalDateTime fillStartTime = fillStart.atStartOfDay();
|
|
|
+ LocalDateTime fillEndTime = today.plusDays(1).atStartOfDay();
|
|
|
|
|
|
QueryWrapper<FhzgSeVoltageEvent> agg = new QueryWrapper<>();
|
|
|
agg.select("alarm_level", "alarm_type", "COUNT(*) AS cnt")
|
|
|
- .ge("trigger_time", yesterdayStart)
|
|
|
- .le("trigger_time", yesterdayEnd)
|
|
|
+ .ge("trigger_time", fillStartTime)
|
|
|
+ .lt("trigger_time", fillEndTime)
|
|
|
.eq("status", 2)
|
|
|
.groupBy("alarm_level", "alarm_type");
|
|
|
if (type == 2) agg.eq("county_id", id);
|
|
|
@@ -416,73 +440,113 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
vo.setHeavyLoadRate(BigDecimal.ZERO);
|
|
|
vo.setOverloadRate(BigDecimal.ZERO);
|
|
|
}
|
|
|
+
|
|
|
+ // 3. 线损电量:从明细表聚合(今日未刷日汇总,用明细实时算)
|
|
|
+ vo.setLineLossKwh(queryLineLossKwhFromDetail(id, type, startTime, endTime));
|
|
|
+
|
|
|
return vo;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 历史供电能力:负载率从日汇总表查,重过载次数从事件表统计
|
|
|
- * month = 月初 ~ 昨天;year = 1.1 ~ 昨天
|
|
|
+ * 历史供电能力(分层口径):
|
|
|
+ * 历史部分(T+1)查日汇总表 [startDate, yesterday] —— 今天尚未入表;
|
|
|
+ * 今日部分实时补:负载率从断面明细聚合、重过载次数从事件表统计、线损从明细 SUM。
|
|
|
+ * month = 月初 ~ 今天;year = 1.1 ~ 今天
|
|
|
*/
|
|
|
private SeCapacityDashboardVO queryCapacityHistory(String id, Integer type, String timeScope) {
|
|
|
LocalDate today = LocalDate.now();
|
|
|
LocalDate startDate;
|
|
|
- LocalDate endDate;
|
|
|
+ LocalDate endDate = today.minusDays(1);
|
|
|
|
|
|
if ("month".equalsIgnoreCase(timeScope)) {
|
|
|
startDate = today.withDayOfMonth(1);
|
|
|
} else {
|
|
|
startDate = LocalDate.of(today.getYear(), 1, 1);
|
|
|
}
|
|
|
- endDate = today.minusDays(1);
|
|
|
|
|
|
- if (endDate.isBefore(startDate)) {
|
|
|
- return SeCapacityDashboardVO.builder().build();
|
|
|
- }
|
|
|
+ // 历史部分统计(日汇总表 T+1,只到昨天)
|
|
|
+ BigDecimal histMaxLoadRate = null;
|
|
|
+ BigDecimal histSumAvg = BigDecimal.ZERO;
|
|
|
+ int histDays = 0;
|
|
|
+ long sumHeavy = 0;
|
|
|
+ long sumOverload = 0;
|
|
|
+ BigDecimal histLineLossKwh = BigDecimal.ZERO;
|
|
|
|
|
|
- // 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);
|
|
|
+ if (!endDate.isBefore(startDate)) {
|
|
|
+ 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()) {
|
|
|
- vo = SeCapacityDashboardVO.builder().build();
|
|
|
- } else {
|
|
|
- BigDecimal maxLoadRate = BigDecimal.ZERO;
|
|
|
- BigDecimal sumAvg = BigDecimal.ZERO;
|
|
|
- long sumHeavy = 0;
|
|
|
- long sumOverload = 0;
|
|
|
for (FhzgSeCapacityDaily d : dailyRecords) {
|
|
|
- if (d.getMaxLoadRate() != null && d.getMaxLoadRate().compareTo(maxLoadRate) > 0) {
|
|
|
- maxLoadRate = d.getMaxLoadRate();
|
|
|
+ if (d.getMaxLoadRate() != null
|
|
|
+ && (histMaxLoadRate == null || d.getMaxLoadRate().compareTo(histMaxLoadRate) > 0)) {
|
|
|
+ histMaxLoadRate = d.getMaxLoadRate();
|
|
|
}
|
|
|
if (d.getAvgLoadRate() != null) {
|
|
|
- sumAvg = sumAvg.add(d.getAvgLoadRate());
|
|
|
+ histSumAvg = histSumAvg.add(d.getAvgLoadRate());
|
|
|
+ histDays++;
|
|
|
}
|
|
|
// 重过载事件数:日统计表存的就是当日事件表事件数,直接累加
|
|
|
if (d.getHeavyCount() != null) sumHeavy += d.getHeavyCount();
|
|
|
if (d.getOverloadCount() != null) sumOverload += d.getOverloadCount();
|
|
|
}
|
|
|
- BigDecimal avgLoadRate = sumAvg.divide(BigDecimal.valueOf(dailyRecords.size()), 2, RoundingMode.HALF_UP);
|
|
|
- int totalEvents = (int) (sumHeavy + sumOverload);
|
|
|
- vo = SeCapacityDashboardVO.builder()
|
|
|
- .maxLoadRate(maxLoadRate)
|
|
|
- .avgLoadRate(avgLoadRate)
|
|
|
- .heavyLoadEventCount((int) sumHeavy)
|
|
|
- .overloadEventCount((int) sumOverload)
|
|
|
- .totalEventCount(totalEvents)
|
|
|
- .build();
|
|
|
- if (totalEvents > 0) {
|
|
|
- vo.setHeavyLoadRate(new BigDecimal(sumHeavy * 100)
|
|
|
- .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
- vo.setOverloadRate(new BigDecimal(sumOverload * 100)
|
|
|
- .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
- } else {
|
|
|
- vo.setHeavyLoadRate(BigDecimal.ZERO);
|
|
|
- vo.setOverloadRate(BigDecimal.ZERO);
|
|
|
- }
|
|
|
+ // 线损电量(历史部分)
|
|
|
+ histLineLossKwh = queryLineLossKwhFromDaily(id, type, startDate, endDate);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 今日部分实时聚合(断面明细 + 事件表 + 线损明细)
|
|
|
+ SeCapacityDashboardVO todayVo = queryCapacityToday(id, type);
|
|
|
+ BigDecimal todayMaxLoadRate = todayVo != null ? todayVo.getMaxLoadRate() : null;
|
|
|
+ BigDecimal todayAvgLoadRate = todayVo != null ? todayVo.getAvgLoadRate() : null;
|
|
|
+ int todayHeavy = todayVo != null ? todayVo.getHeavyLoadEventCount() : 0;
|
|
|
+ int todayOverload = todayVo != null ? todayVo.getOverloadEventCount() : 0;
|
|
|
+ BigDecimal todayLineLoss = todayVo != null ? todayVo.getLineLossKwh() : null;
|
|
|
+
|
|
|
+ // 合并
|
|
|
+ BigDecimal maxLoadRate = histMaxLoadRate;
|
|
|
+ if (todayMaxLoadRate != null
|
|
|
+ && (maxLoadRate == null || todayMaxLoadRate.compareTo(maxLoadRate) > 0)) {
|
|
|
+ maxLoadRate = todayMaxLoadRate;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 平均负载率:加权平均(历史每天一个均值 + 今日均值)
|
|
|
+ BigDecimal avgLoadRate = null;
|
|
|
+ if (todayAvgLoadRate != null && histDays > 0) {
|
|
|
+ avgLoadRate = histSumAvg.add(todayAvgLoadRate)
|
|
|
+ .divide(BigDecimal.valueOf(histDays + 1), 2, RoundingMode.HALF_UP);
|
|
|
+ } else if (todayAvgLoadRate != null) {
|
|
|
+ avgLoadRate = todayAvgLoadRate;
|
|
|
+ } else if (histDays > 0) {
|
|
|
+ avgLoadRate = histSumAvg.divide(BigDecimal.valueOf(histDays), 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ long totalHeavy = sumHeavy + todayHeavy;
|
|
|
+ long totalOverload = sumOverload + todayOverload;
|
|
|
+ long totalEvents = totalHeavy + totalOverload;
|
|
|
+
|
|
|
+ BigDecimal lineLossKwh = histLineLossKwh;
|
|
|
+ if (todayLineLoss != null) {
|
|
|
+ lineLossKwh = lineLossKwh.add(todayLineLoss);
|
|
|
+ }
|
|
|
+
|
|
|
+ SeCapacityDashboardVO vo = SeCapacityDashboardVO.builder()
|
|
|
+ .maxLoadRate(maxLoadRate)
|
|
|
+ .avgLoadRate(avgLoadRate)
|
|
|
+ .heavyLoadEventCount((int) totalHeavy)
|
|
|
+ .overloadEventCount((int) totalOverload)
|
|
|
+ .totalEventCount((int) totalEvents)
|
|
|
+ .lineLossKwh(lineLossKwh)
|
|
|
+ .build();
|
|
|
+ if (totalEvents > 0) {
|
|
|
+ vo.setHeavyLoadRate(new BigDecimal(totalHeavy * 100)
|
|
|
+ .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
+ vo.setOverloadRate(new BigDecimal(totalOverload * 100)
|
|
|
+ .divide(BigDecimal.valueOf(totalEvents), 2, RoundingMode.HALF_UP));
|
|
|
+ } else {
|
|
|
+ vo.setHeavyLoadRate(BigDecimal.ZERO);
|
|
|
+ vo.setOverloadRate(BigDecimal.ZERO);
|
|
|
}
|
|
|
|
|
|
return vo;
|
|
|
@@ -652,11 +716,15 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
endDate = yesterday;
|
|
|
}
|
|
|
|
|
|
- // 分子:中台区间 + 事件表补区间
|
|
|
+ // 分子:中台区间 + 事件表补区间(补差起点 = max(中台最后一天+1, 业务起点),跨月/跨年不越界)
|
|
|
BigDecimal zhongtaiHours = sumZhongtaiOverLimitHours(id, type, startDate, endDate);
|
|
|
- BigDecimal eventHours = endDate.isBefore(today)
|
|
|
+ LocalDate fillStart = endDate.plusDays(1);
|
|
|
+ if (fillStart.isBefore(startDate)) {
|
|
|
+ fillStart = startDate;
|
|
|
+ }
|
|
|
+ BigDecimal eventHours = fillStart.isBefore(today)
|
|
|
? sumConsumerEventHours(id, type,
|
|
|
- endDate.plusDays(1).atStartOfDay(), today.plusDays(1).atStartOfDay())
|
|
|
+ fillStart.atStartOfDay(), today.plusDays(1).atStartOfDay())
|
|
|
: BigDecimal.ZERO;
|
|
|
overLimitHours = zhongtaiHours.add(eventHours);
|
|
|
|
|
|
@@ -779,4 +847,48 @@ public class SeIndicatorServiceImpl implements SeIndicatorService {
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
+ // ============================================================
|
|
|
+ // 8. 线损电量查询
|
|
|
+ // ============================================================
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 今日线损电量:从明细表聚合 SUM(line_loss_kw) × 0.25h
|
|
|
+ */
|
|
|
+ private BigDecimal queryLineLossKwhFromDetail(String id, Integer type,
|
|
|
+ LocalDateTime startTime, LocalDateTime endTime) {
|
|
|
+ QueryWrapper<FhzgSeLineLossDetail> qw = new QueryWrapper<>();
|
|
|
+ qw.select("COALESCE(SUM(line_loss_kw), 0) AS total_loss");
|
|
|
+ if (type == 2) qw.eq("county_id", id);
|
|
|
+ else if (type == 3) qw.eq("subs_id", id);
|
|
|
+ else if (type == 4) qw.eq("feeder_id", id);
|
|
|
+ qw.ge("snap_time", startTime).lt("snap_time", endTime);
|
|
|
+ List<Map<String, Object>> rows = lineLossDetailMapper.selectMaps(qw);
|
|
|
+ if (rows != null && !rows.isEmpty() && rows.get(0).get("total_loss") != null) {
|
|
|
+ BigDecimal sumKw = ((Number) rows.get(0).get("total_loss")).longValue() == 0
|
|
|
+ ? BigDecimal.ZERO
|
|
|
+ : new BigDecimal(rows.get(0).get("total_loss").toString());
|
|
|
+ // 每个断面间隔15min = 0.25h,线损功率 × 时间 = 电量
|
|
|
+ return sumKw.multiply(new BigDecimal("0.25")).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 历史线损电量:从日汇总表聚合 SUM(line_loss_kwh)
|
|
|
+ */
|
|
|
+ private BigDecimal queryLineLossKwhFromDaily(String id, Integer type,
|
|
|
+ LocalDate startDate, LocalDate endDate) {
|
|
|
+ QueryWrapper<FhzgSeLineLossDaily> qw = new QueryWrapper<>();
|
|
|
+ qw.select("COALESCE(SUM(line_loss_kwh), 0) AS total_kwh");
|
|
|
+ if (type == 2) qw.eq("county_id", id);
|
|
|
+ else if (type == 3) qw.eq("subs_id", id);
|
|
|
+ else if (type == 4) qw.eq("feeder_id", id);
|
|
|
+ qw.ge("stat_date", startDate).le("stat_date", endDate);
|
|
|
+ List<Map<String, Object>> rows = lineLossDailyMapper.selectMaps(qw);
|
|
|
+ if (rows != null && !rows.isEmpty() && rows.get(0).get("total_kwh") != null) {
|
|
|
+ return new BigDecimal(rows.get(0).get("total_kwh").toString()).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
}
|