|
|
@@ -22,6 +22,7 @@ import com.usky.vpp.service.vo.DrMonitorCurveVO;
|
|
|
import com.usky.vpp.service.vo.DrMonitorRecordVO;
|
|
|
import com.usky.vpp.service.vo.DrMonitorSummaryVO;
|
|
|
import com.usky.vpp.service.vo.SiteBaselineVO;
|
|
|
+import com.usky.vpp.service.vo.SiteDeclaredCapacityVO;
|
|
|
import com.usky.vpp.util.VppAuditHelper;
|
|
|
import com.usky.vpp.util.VppPageHelper;
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
@@ -257,62 +258,50 @@ public class VppDrMonitorServiceImpl implements VppDrMonitorService {
|
|
|
|
|
|
List<VppDrInvitation> invitations = listInvitations(
|
|
|
Collections.singleton(event.getId()), peakSiteIds, tenantId);
|
|
|
- BigDecimal declaredSum = BigDecimal.ZERO;
|
|
|
- BigDecimal actualSum = BigDecimal.ZERO;
|
|
|
+ Map<Long, BigDecimal> invitationActualBySite = new HashMap<>();
|
|
|
for (VppDrInvitation invitation : invitations) {
|
|
|
- declaredSum = declaredSum.add(nz(invitation.getDeclaredCapacityKw()));
|
|
|
- actualSum = actualSum.add(nz(invitation.getActualResponseCapacityKw()));
|
|
|
+ if (invitation.getSiteId() == null) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ invitationActualBySite.merge(invitation.getSiteId(),
|
|
|
+ nz(invitation.getActualResponseCapacityKw()), BigDecimal::add);
|
|
|
}
|
|
|
- BigDecimal declaredAvg = avg(declaredSum, resourceCount);
|
|
|
- BigDecimal actualAvg = avg(actualSum, resourceCount);
|
|
|
|
|
|
LocalDateTime windowStart = event.getStartTime().minusHours(2);
|
|
|
LocalDateTime windowEnd = (event.getEndTime() != null ? event.getEndTime() : event.getStartTime()).plusHours(1);
|
|
|
String responseStartTime = event.getStartTime().format(DATE_TIME_FMT);
|
|
|
+ String eventEndTime = (event.getEndTime() != null ? event.getEndTime() : event.getStartTime()).format(DATE_TIME_FMT);
|
|
|
String actualEndTime = windowEnd.format(DATE_TIME_FMT);
|
|
|
+ int requiredDays = (baselineDays != null && baselineDays == 3) ? 3 : 5;
|
|
|
|
|
|
- Map<String, BigDecimal> baseline5Weighted = new LinkedHashMap<>();
|
|
|
- Map<String, BigDecimal> baseline3Weighted = new LinkedHashMap<>();
|
|
|
- Map<String, BigDecimal> loadWeighted = new LinkedHashMap<>();
|
|
|
+ BigDecimal actualSum = BigDecimal.ZERO;
|
|
|
+ for (Long siteId : peakSiteIds) {
|
|
|
+ actualSum = actualSum.add(resolveSiteActualResponseKw(
|
|
|
+ siteId, responseStartTime, eventEndTime, invitationActualBySite.get(siteId)));
|
|
|
+ }
|
|
|
+ BigDecimal actualAvg = avg(actualSum, resourceCount);
|
|
|
+
|
|
|
+ Map<String, BigDecimal> baselineWeighted = new LinkedHashMap<>();
|
|
|
Set<String> dataSources = new LinkedHashSet<>();
|
|
|
List<Long> usedSiteIds = new ArrayList<>();
|
|
|
|
|
|
for (Map.Entry<Long, Long> entry : siteResourceCount.entrySet()) {
|
|
|
Long siteId = entry.getKey();
|
|
|
BigDecimal weight = BigDecimal.valueOf(entry.getValue());
|
|
|
- SiteBaselineVO baseline5 = baselineService.getSiteBaseline(siteId, responseStartTime, 5, actualEndTime);
|
|
|
- SiteBaselineVO baseline3 = baselineService.getSiteBaseline(siteId, responseStartTime, 3, actualEndTime);
|
|
|
- if ((baseline5 == null || CollectionUtils.isEmpty(baseline5.getPoints()))
|
|
|
- && (baseline3 == null || CollectionUtils.isEmpty(baseline3.getPoints()))) {
|
|
|
+ SiteBaselineVO baseline = baselineService.getSiteBaseline(siteId, responseStartTime, requiredDays, actualEndTime);
|
|
|
+ if (baseline == null || CollectionUtils.isEmpty(baseline.getPoints())) {
|
|
|
continue;
|
|
|
}
|
|
|
usedSiteIds.add(siteId);
|
|
|
- if (baseline5 != null && StringUtils.hasText(baseline5.getDataSource())) {
|
|
|
- dataSources.add(baseline5.getDataSource());
|
|
|
+ if (StringUtils.hasText(baseline.getDataSource())) {
|
|
|
+ dataSources.add(baseline.getDataSource());
|
|
|
}
|
|
|
- if (baseline5 != null && !CollectionUtils.isEmpty(baseline5.getPoints())) {
|
|
|
- for (BaselinePointVO point : baseline5.getPoints()) {
|
|
|
- if (!StringUtils.hasText(point.getTime()) || !inCurveWindow(point.getTime(), windowStart, windowEnd)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- baseline5Weighted.merge(point.getTime(),
|
|
|
- nz(point.getPredictedBaselineKw()).multiply(weight), BigDecimal::add);
|
|
|
- loadWeighted.merge(point.getTime(),
|
|
|
- nz(point.getTodayActualKw()).multiply(weight), BigDecimal::add);
|
|
|
- }
|
|
|
- }
|
|
|
- if (baseline3 != null && !CollectionUtils.isEmpty(baseline3.getPoints())) {
|
|
|
- for (BaselinePointVO point : baseline3.getPoints()) {
|
|
|
- if (!StringUtils.hasText(point.getTime()) || !inCurveWindow(point.getTime(), windowStart, windowEnd)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- baseline3Weighted.merge(point.getTime(),
|
|
|
- nz(point.getPredictedBaselineKw()).multiply(weight), BigDecimal::add);
|
|
|
- if (!loadWeighted.containsKey(point.getTime())) {
|
|
|
- loadWeighted.merge(point.getTime(),
|
|
|
- nz(point.getTodayActualKw()).multiply(weight), BigDecimal::add);
|
|
|
- }
|
|
|
+ for (BaselinePointVO point : baseline.getPoints()) {
|
|
|
+ if (!StringUtils.hasText(point.getTime()) || !inCurveWindow(point.getTime(), windowStart, windowEnd)) {
|
|
|
+ continue;
|
|
|
}
|
|
|
+ baselineWeighted.merge(point.getTime(),
|
|
|
+ nz(point.getPredictedBaselineKw()).multiply(weight), BigDecimal::add);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -322,7 +311,6 @@ public class VppDrMonitorServiceImpl implements VppDrMonitorService {
|
|
|
curve.setEventId(event.getEventId());
|
|
|
curve.setResponseDate(event.getStartTime().toLocalDate().format(DATE_FMT));
|
|
|
curve.setSiteIds(usedSiteIds);
|
|
|
- curve.setDeclaredCapacityKw(declaredAvg);
|
|
|
curve.setActualResponseCapacityKw(actualAvg);
|
|
|
if (dataSources.isEmpty()) {
|
|
|
curve.setDataSource("mock");
|
|
|
@@ -332,35 +320,41 @@ public class VppDrMonitorServiceImpl implements VppDrMonitorService {
|
|
|
curve.setDataSource("mixed");
|
|
|
}
|
|
|
|
|
|
- Set<String> timeSet = new LinkedHashSet<>();
|
|
|
- timeSet.addAll(baseline5Weighted.keySet());
|
|
|
- timeSet.addAll(baseline3Weighted.keySet());
|
|
|
- timeSet.addAll(loadWeighted.keySet());
|
|
|
- List<String> times = new ArrayList<>(timeSet);
|
|
|
+ List<String> times = new ArrayList<>(baselineWeighted.keySet());
|
|
|
times.sort(Comparator.naturalOrder());
|
|
|
for (String time : times) {
|
|
|
DrMonitorCurveVO.Point point = new DrMonitorCurveVO.Point();
|
|
|
point.setTime(time);
|
|
|
- BigDecimal b5 = baseline5Weighted.getOrDefault(time, BigDecimal.ZERO)
|
|
|
- .divide(divisor, SCALE, RoundingMode.HALF_UP);
|
|
|
- BigDecimal b3 = baseline3Weighted.getOrDefault(time, BigDecimal.ZERO)
|
|
|
- .divide(divisor, SCALE, RoundingMode.HALF_UP);
|
|
|
- point.setBaseline5DayKw(b5);
|
|
|
- point.setBaseline3DayKw(b3);
|
|
|
- if (baselineDays != null && baselineDays == 3) {
|
|
|
- point.setBaselineKw(b3);
|
|
|
- } else {
|
|
|
- point.setBaselineKw(b5);
|
|
|
- }
|
|
|
- point.setLoadKw(loadWeighted.getOrDefault(time, BigDecimal.ZERO)
|
|
|
+ point.setBaselineKw(baselineWeighted.getOrDefault(time, BigDecimal.ZERO)
|
|
|
.divide(divisor, SCALE, RoundingMode.HALF_UP));
|
|
|
- point.setDeclaredCapacityKw(declaredAvg);
|
|
|
point.setActualResponseCapacityKw(actualAvg);
|
|
|
curve.getPoints().add(point);
|
|
|
}
|
|
|
return curve;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 实际响应容量复用申报容量链路 {@link VppBaselineService#getSiteDeclaredCapacity},
|
|
|
+ * 取预估响应容量;无数据时回退邀约实际响应容量。
|
|
|
+ */
|
|
|
+ private BigDecimal resolveSiteActualResponseKw(Long siteId, String responseStartTime,
|
|
|
+ String responseEndTime, BigDecimal fallbackKw) {
|
|
|
+ if (siteId == null || !StringUtils.hasText(responseStartTime) || !StringUtils.hasText(responseEndTime)) {
|
|
|
+ return nz(fallbackKw);
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ SiteDeclaredCapacityVO capacity = baselineService.getSiteDeclaredCapacity(
|
|
|
+ siteId, responseStartTime, responseEndTime);
|
|
|
+ if (capacity != null && capacity.getEstimatedResponseCapacityKw() != null
|
|
|
+ && capacity.getEstimatedResponseCapacityKw().compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ return capacity.getEstimatedResponseCapacityKw();
|
|
|
+ }
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ // 回退邀约实际响应容量,保持曲线可返回
|
|
|
+ }
|
|
|
+ return nz(fallbackKw);
|
|
|
+ }
|
|
|
+
|
|
|
private boolean inCurveWindow(String timeKey, LocalDateTime windowStart, LocalDateTime windowEnd) {
|
|
|
try {
|
|
|
LocalTime t = LocalTime.parse(timeKey.length() == 5 ? timeKey : timeKey.substring(0, 5));
|