|
@@ -1,28 +1,30 @@
|
|
|
package com.bizmatics.service.impl;
|
|
|
|
|
|
-
|
|
|
import cn.afterturn.easypoi.excel.ExcelExportUtil;
|
|
|
import cn.afterturn.easypoi.excel.entity.ExportParams;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
import com.bizmatics.common.core.exception.BusinessException;
|
|
|
-import com.bizmatics.common.core.util.Arith;
|
|
|
-import com.bizmatics.common.core.util.BeanMapperUtils;
|
|
|
-import com.bizmatics.common.core.util.DateUtils;
|
|
|
-import com.bizmatics.common.core.util.FileUtils;
|
|
|
+import com.bizmatics.common.core.util.*;
|
|
|
import com.bizmatics.common.mvc.base.AbstractCrudService;
|
|
|
import com.bizmatics.common.spring.util.GlobalUtils;
|
|
|
import com.bizmatics.common.spring.util.JsonUtils;
|
|
|
import com.bizmatics.model.*;
|
|
|
+import com.bizmatics.model.utils.TimeRangeParams;
|
|
|
+import com.bizmatics.model.utils.TimeRangeUtils;
|
|
|
import com.bizmatics.model.vo.*;
|
|
|
-import com.bizmatics.persistence.mapper.HtAnalogDataMapper;
|
|
|
+import com.bizmatics.persistence.mapper.*;
|
|
|
import com.bizmatics.service.*;
|
|
|
+import com.bizmatics.service.util.AnalogCache;
|
|
|
import com.bizmatics.service.util.FieldEscapeUtils;
|
|
|
import com.bizmatics.service.util.SecurityUtils;
|
|
|
+import com.bizmatics.service.util.SiteFeeCacheService;
|
|
|
import com.bizmatics.service.vo.*;
|
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|
|
+import org.checkerframework.checker.units.qual.A;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
@@ -30,9 +32,13 @@ import java.io.File;
|
|
|
import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
import java.text.DateFormat;
|
|
|
import java.text.DecimalFormat;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
+import java.time.*;
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
+import java.time.temporal.TemporalAdjusters;
|
|
|
import java.util.*;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
import java.util.stream.Collectors;
|
|
@@ -45,10 +51,10 @@ import static com.bizmatics.service.impl.RtAnalogDataServiceImpl.getLastDayOfMon
|
|
|
* @author yq
|
|
|
* @date 2021/7/20 16:49
|
|
|
*/
|
|
|
+@Slf4j
|
|
|
@Service
|
|
|
public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMapper, HtAnalogData> implements HtAnalogDataService {
|
|
|
|
|
|
-
|
|
|
@Autowired
|
|
|
private HadSiteStaticService hadSiteStaticService;
|
|
|
@Autowired
|
|
@@ -60,6 +66,27 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
private SiteDynamicPropertiesService siteDynamicPropertiesService;
|
|
|
@Autowired
|
|
|
private DeviceAttributeService deviceAttributeService;
|
|
|
+ @Autowired
|
|
|
+ private HtAnalogDataMapper htAnalogDataMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DeviceMapper deviceMapper;
|
|
|
+ @Autowired
|
|
|
+ private HtAnalog173DataMapper htAnalog173DataMapper;
|
|
|
+ @Autowired
|
|
|
+ private ElectricityRateConfigMapper electricityRateConfigMapper;
|
|
|
+ @Autowired
|
|
|
+ private SiteInformationMapper siteInformationMapper;
|
|
|
+ @Autowired
|
|
|
+ private SiteElectricityRecordMapper siteElectricityRecordMapper;
|
|
|
+ @Autowired
|
|
|
+ private ElectricityTimePriceMapper electricityTimePriceMapper;
|
|
|
+ @Autowired
|
|
|
+ private AnalogCache analogCache;
|
|
|
+ @Autowired
|
|
|
+ private SiteFeeCacheService siteFeeCacheService;
|
|
|
+
|
|
|
+ private static final BigDecimal ZERO = BigDecimal.ZERO;
|
|
|
|
|
|
@Override
|
|
|
public HadCountVO selectCount() {
|
|
@@ -99,7 +126,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
List<Object> dates = new ArrayList<>();
|
|
|
dates.add("00:00:00");
|
|
|
for (int i = 2; i < 24; i += 2) {
|
|
|
- //结束时间
|
|
|
+ // 结束时间
|
|
|
Date hours = DateUtils.setHours(startTime, i);
|
|
|
startTime = hours;
|
|
|
dates.add(DateUtils.getTime(hours));
|
|
@@ -128,7 +155,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
List<Object> dates = new ArrayList<>();
|
|
|
dates.add("00:00:00");
|
|
|
for (int i = 2; i < 24; i += 2) {
|
|
|
- //结束时间
|
|
|
+ // 结束时间
|
|
|
Date hours = DateUtils.setHours(startTime, i);
|
|
|
objects.add(0.0);
|
|
|
startTime = hours;
|
|
@@ -166,11 +193,11 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
public HadCountVO getCountBySite(Integer siteId) {
|
|
|
Integer userId = SecurityUtils.getLoginUser().getUser().getUserId().intValue();
|
|
|
Date date = new Date();
|
|
|
- //当日开始时间
|
|
|
+ // 当日开始时间
|
|
|
Date firstDayOfDate = DateUtils.getDayStartTime(date);
|
|
|
- //当月开始时间
|
|
|
+ // 当月开始时间
|
|
|
Date firstDayOfMonth = DateUtils.getFirstDayOfMonth(date);
|
|
|
- //当年开始时间
|
|
|
+ // 当年开始时间
|
|
|
Date firstDayOfYear = DateUtils.getBeginDayOfYear(date);
|
|
|
HadCountVO hadCountVO = new HadCountVO();
|
|
|
hadCountVO.setDayCount(hadSiteStaticService.getCount(userId, DateUtils.getDayStartTime(date), date, siteId));
|
|
@@ -280,7 +307,13 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
date = hours;
|
|
|
Date finalDate = date;
|
|
|
Optional<HtAnalogData> htAnalogData = Optional.ofNullable(htList).flatMap(hts -> hts.stream()
|
|
|
- .filter(hads -> DateUtils.isEffectiveDate(hads.getDataTime(), finalDate, hours))
|
|
|
+ .filter(hads -> {
|
|
|
+ // LocalDateTime 转 Date
|
|
|
+ Date date1 = Date.from(hads.getDataTime()
|
|
|
+ .atZone(ZoneId.systemDefault())
|
|
|
+ .toInstant());
|
|
|
+ return DateUtils.isEffectiveDate(date1, finalDate, hours);
|
|
|
+ })
|
|
|
.findFirst());
|
|
|
iaList.add(htAnalogData.map(HtAnalogData::getIa).orElse(0.00));
|
|
|
ibList.add(htAnalogData.map(HtAnalogData::getIb).orElse(0.00));
|
|
@@ -304,7 +337,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
public List<RealScoreVO> rtRealScore(String deviceCode, Date startTime, Date endTime) {
|
|
|
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
- //查询设备
|
|
|
+ // 查询设备
|
|
|
LambdaQueryWrapper<Device> deviceQuery = Wrappers.lambdaQuery();
|
|
|
deviceQuery.eq(Device::getDeviceCode, deviceCode);
|
|
|
Device device = deviceService.getOne(deviceQuery);
|
|
@@ -318,7 +351,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
}
|
|
|
List<HtAnalogData> list = baseMapper.getDemandAnalysisList(deviceCode, formatter.format(startTime), formatter.format(endTime), table);
|
|
|
|
|
|
- //查询sd
|
|
|
+ // 查询sd
|
|
|
LambdaQueryWrapper<SiteDynamicProperties> sdQuery = Wrappers.lambdaQuery();
|
|
|
sdQuery.eq(SiteDynamicProperties::getSiteId, device.getSiteId());
|
|
|
SiteDynamicProperties siteDynamicProperties = siteDynamicPropertiesService.getOne(sdQuery);
|
|
@@ -395,25 +428,25 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
deviceAnalogVariableList.setVariableCoding(dataManagementOneVO.getDisplayField().get(i).split("_")[0] + "_" + dataManagementOneVO.getDisplayField().get(i).split("_")[1]);
|
|
|
variableCodingList.add(deviceAnalogVariableList);
|
|
|
}
|
|
|
- //通信设备编号
|
|
|
+ // 通信设备编号
|
|
|
Set set = new HashSet();
|
|
|
List<DataManagementVO> newList = new ArrayList();
|
|
|
set.addAll(dataManagementVOList);
|
|
|
newList.addAll(set);
|
|
|
|
|
|
- //显示的字段名
|
|
|
+ // 显示的字段名
|
|
|
Set set1 = new HashSet();
|
|
|
List<String> list = new ArrayList();
|
|
|
set1.addAll(newListOne);
|
|
|
list.addAll(set1);
|
|
|
|
|
|
- //监控ID
|
|
|
+ // 监控ID
|
|
|
Set set2 = new HashSet();
|
|
|
List<String> monitor_list = new ArrayList();
|
|
|
set2.addAll(newListTwo);
|
|
|
monitor_list.addAll(set2);
|
|
|
|
|
|
- //查询字段
|
|
|
+ // 查询字段
|
|
|
Set set3 = new HashSet();
|
|
|
List<String> fieldDisplayOne = new ArrayList();
|
|
|
set3.addAll(fieldDisplay);
|
|
@@ -444,15 +477,15 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
List<ContextualDataVo> yearOnYearList3 = new ArrayList<>();
|
|
|
if (fieldDisplayOne183.size() > 0) {
|
|
|
List<String> fieldDisplayList = FieldEscapeUtils.getSyllable(type, valueCalculation, fieldDisplayOne183);
|
|
|
- yearOnYearList1 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_data", 0,type);
|
|
|
+ yearOnYearList1 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_data", 0, type);
|
|
|
}
|
|
|
if (fieldDisplayOne171.size() > 0) {
|
|
|
List<String> fieldDisplayList = FieldEscapeUtils.getSyllable(type, valueCalculation, fieldDisplayOne171);
|
|
|
- yearOnYearList2 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_171_data", 0,type);
|
|
|
+ yearOnYearList2 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_171_data", 0, type);
|
|
|
}
|
|
|
if (fieldDisplayOne173.size() > 0) {
|
|
|
List<String> fieldDisplayList = FieldEscapeUtils.getSyllable(type, valueCalculation, fieldDisplayOne173);
|
|
|
- yearOnYearList3 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_173_data", 0,type);
|
|
|
+ yearOnYearList3 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_173_data", 0, type);
|
|
|
}
|
|
|
List<ContextualDataVo> yearOnYearList4 = Stream.of(yearOnYearList1, yearOnYearList2).flatMap(Collection::stream).distinct().collect(Collectors.toList());
|
|
|
List<ContextualDataVo> yearOnYearList = Stream.of(yearOnYearList3, yearOnYearList4).flatMap(Collection::stream).distinct().collect(Collectors.toList());
|
|
@@ -658,15 +691,15 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
List<ContextualDataVo> yearOnYearList3 = new ArrayList<>();
|
|
|
if (fieldDisplayOne183.size() > 0) {
|
|
|
List<String> fieldDisplayList = FieldEscapeUtils.getSyllable(type, valueCalculation, fieldDisplayOne183);
|
|
|
- yearOnYearList1 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_data", 0,type);
|
|
|
+ yearOnYearList1 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_data", 0, type);
|
|
|
}
|
|
|
if (fieldDisplayOne171.size() > 0) {
|
|
|
List<String> fieldDisplayList = FieldEscapeUtils.getSyllable(type, valueCalculation, fieldDisplayOne171);
|
|
|
- yearOnYearList2 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_171_data", 0,type);
|
|
|
+ yearOnYearList2 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_171_data", 0, type);
|
|
|
}
|
|
|
if (fieldDisplayOne173.size() > 0) {
|
|
|
List<String> fieldDisplayList = FieldEscapeUtils.getSyllable(type, valueCalculation, fieldDisplayOne173);
|
|
|
- yearOnYearList3 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_173_data", 0,type);
|
|
|
+ yearOnYearList3 = baseMapper.getYearOnYearThree(newList, dataManagementOneVO.getStartTime(), dataManagementOneVO.getEndTime(), variableCodingList, fieldDisplayList, "ht_analog_173_data", 0, type);
|
|
|
}
|
|
|
List<ContextualDataVo> yearOnYearList4 = Stream.of(yearOnYearList1, yearOnYearList2).flatMap(Collection::stream).distinct().collect(Collectors.toList());
|
|
|
List<ContextualDataVo> currentPeriodRingRatioList = Stream.of(yearOnYearList3, yearOnYearList4).flatMap(Collection::stream).distinct().collect(Collectors.toList());
|
|
@@ -818,10 +851,10 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
queryWrapper.eq(Device::getDeviceCode, deviceCode);
|
|
|
List<Device> deviceList = deviceService.list(queryWrapper);
|
|
|
String table = "ht_analog_data";
|
|
|
- if (deviceList.size() > 0) {
|
|
|
- if (deviceList.get(0).getDeviceType().equals("1")) {
|
|
|
+ if (!deviceList.isEmpty()) {
|
|
|
+ if ("1".equals(deviceList.get(0).getDeviceType())) {
|
|
|
table = "ht_analog_data";
|
|
|
- } else if (deviceList.get(0).getDeviceType().equals("4")) {
|
|
|
+ } else if ("4".equals(deviceList.get(0).getDeviceType())) {
|
|
|
table = "ht_analog_173_data";
|
|
|
} else {
|
|
|
throw new BusinessException("173用电设备无用电数据采集");
|
|
@@ -832,7 +865,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
|
|
|
List<HtAnalogDataVo> maxMonthlyReport = baseMapper.getEnergyUseList(deviceCode, startTime, endTime, cycle, 1, table);
|
|
|
List<HtAnalogDataVo> minMonthlyReport = baseMapper.getEnergyUseList(deviceCode, startTime, endTime, cycle, 2, table);
|
|
|
- if (maxMonthlyReport.size() > 0) {
|
|
|
+ if (!maxMonthlyReport.isEmpty()) {
|
|
|
for (int i = 0; i < maxMonthlyReport.size(); i++) {
|
|
|
BigDecimal b1 = new BigDecimal(maxMonthlyReport.get(i).getEpp().toString());
|
|
|
BigDecimal b2 = new BigDecimal(minMonthlyReport.get(i).getEpp().toString());
|
|
@@ -874,7 +907,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
queryWrapper1.eq(Device::getDeviceCode, deviceCode);
|
|
|
List<Device> deviceList = deviceService.list(queryWrapper1);
|
|
|
String table = "ht_analog_data";
|
|
|
- if (deviceList.size() > 0) {
|
|
|
+ if (!deviceList.isEmpty()) {
|
|
|
if (deviceList.get(0).getDeviceType().equals("1")) {
|
|
|
table = "ht_analog_data";
|
|
|
} else if (deviceList.get(0).getDeviceType().equals("4")) {
|
|
@@ -1100,7 +1133,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgIa());
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgIb());
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgIc());
|
|
|
- //电流不平衡(平均)
|
|
|
+ // 电流不平衡(平均)
|
|
|
Double AvgElBalun = checkBalun(checkList) * 100;
|
|
|
singleLoopReportOneVo.setAvgElBalun(Double.valueOf(df.format(AvgElBalun)));
|
|
|
if (AvgElBalun < 15) {
|
|
@@ -1113,7 +1146,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxIa());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxIb());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxIc());
|
|
|
- //电流不平衡(最大)
|
|
|
+ // 电流不平衡(最大)
|
|
|
Double MaxElBalun = checkBalun(checkList) * 100;
|
|
|
singleLoopReportOneVo.setMaxElBalun(Double.valueOf(df.format(MaxElBalun)));
|
|
|
if (MaxElBalun < 15) {
|
|
@@ -1126,7 +1159,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinIa());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinIb());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinIc());
|
|
|
- //电流不平衡(最小)
|
|
|
+ // 电流不平衡(最小)
|
|
|
Double MinElBalun = checkBalun(checkList) * 100;
|
|
|
singleLoopReportOneVo.setMinElBalun(Double.valueOf(df.format(MinElBalun)));
|
|
|
if (MinElBalun < 15) {
|
|
@@ -1144,7 +1177,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgUa());
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgUb());
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgUc());
|
|
|
- //电压不平衡(平均)
|
|
|
+ // 电压不平衡(平均)
|
|
|
Double AvgVtBalun = checkBalun(checkList) * 100;
|
|
|
singleLoopReportOneVo.setAvgVtBalun(Double.valueOf(df.format(AvgVtBalun)));
|
|
|
if (AvgVtBalun < 15) {
|
|
@@ -1157,7 +1190,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxUa());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxUb());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxUc());
|
|
|
- //电压不平衡(最大)
|
|
|
+ // 电压不平衡(最大)
|
|
|
Double MaxVtBalun = checkBalun(checkList) * 100;
|
|
|
singleLoopReportOneVo.setMaxVtBalun(Double.valueOf(df.format(MaxVtBalun)));
|
|
|
if (MaxVtBalun < 15) {
|
|
@@ -1170,7 +1203,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinUa());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinUb());
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinUc());
|
|
|
- //电压不平衡(最小)
|
|
|
+ // 电压不平衡(最小)
|
|
|
Double MinVtBalun = checkBalun(checkList) * 100;
|
|
|
singleLoopReportOneVo.setMinVtBalun(Double.valueOf(df.format(MinVtBalun)));
|
|
|
if (MinVtBalun < 15) {
|
|
@@ -1189,7 +1222,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
double voltageLevel = Double.parseDouble(singleLoopReportOneVo.getVoltageLevel());
|
|
|
double voltageLevelWanting = voltageLevel / 100 * 7;
|
|
|
|
|
|
- //A相电压合格率(平均)
|
|
|
+ // A相电压合格率(平均)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgUa());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1200,7 +1233,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setAvgUaStatus(false);
|
|
|
}
|
|
|
- //B相电压合格率(平均)
|
|
|
+ // B相电压合格率(平均)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgUb());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1211,7 +1244,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setAvgUbStatus(false);
|
|
|
}
|
|
|
- //C相电压合格率(平均)
|
|
|
+ // C相电压合格率(平均)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getAvgUc());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1222,7 +1255,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setAvgUcStatus(false);
|
|
|
}
|
|
|
- //A相电压合格率(最大)
|
|
|
+ // A相电压合格率(最大)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxUa());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1233,7 +1266,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setMaxUaStatus(false);
|
|
|
}
|
|
|
- //B相电压合格率(最大)
|
|
|
+ // B相电压合格率(最大)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxUb());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1244,7 +1277,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setMaxUbStatus(false);
|
|
|
}
|
|
|
- //C相电压合格率(最大)
|
|
|
+ // C相电压合格率(最大)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getMaxUc());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1255,7 +1288,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setMaxUcStatus(false);
|
|
|
}
|
|
|
- //A相电压合格率(最小)
|
|
|
+ // A相电压合格率(最小)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinUa());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1266,7 +1299,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setMinUaStatus(false);
|
|
|
}
|
|
|
- //B相电压合格率(最小)
|
|
|
+ // B相电压合格率(最小)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinUb());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1277,7 +1310,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setMinUbStatus(false);
|
|
|
}
|
|
|
- //C相电压合格率(最小)
|
|
|
+ // C相电压合格率(最小)
|
|
|
checkList.clear();
|
|
|
checkList.add(SingleLoopReportList.get(0).getMinUc());
|
|
|
checkList.add(voltageLevel);
|
|
@@ -1308,7 +1341,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
}
|
|
|
|
|
|
|
|
|
- //频率(平均)
|
|
|
+ // 频率(平均)
|
|
|
Double cAvgF = 0.00;
|
|
|
if (SingleLoopReportList.get(0).getAvgF() >= 50) {
|
|
|
cAvgF = Double.valueOf(df.format(SingleLoopReportList.get(0).getAvgF() - 50.00));
|
|
@@ -1321,7 +1354,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setAvgFStatus(false);
|
|
|
}
|
|
|
- //频率(最大)
|
|
|
+ // 频率(最大)
|
|
|
Double cMaxF = 0.00;
|
|
|
if (SingleLoopReportList.get(0).getAvgF() >= 50) {
|
|
|
cMaxF = Double.valueOf(df.format(SingleLoopReportList.get(0).getMaxF() - 50.00));
|
|
@@ -1334,7 +1367,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
} else {
|
|
|
singleLoopReportOneVo.setMaxFStatus(false);
|
|
|
}
|
|
|
- //频率(最小)
|
|
|
+ // 频率(最小)
|
|
|
Double cMinF = 0.00;
|
|
|
if (SingleLoopReportList.get(0).getAvgF() >= 50) {
|
|
|
cMinF = Double.valueOf(df.format(SingleLoopReportList.get(0).getMinF() - 50.00));
|
|
@@ -1406,7 +1439,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(RtAnalogDataList.get(i).getIa());
|
|
|
checkList.add(RtAnalogDataList.get(i).getIb());
|
|
|
checkList.add(RtAnalogDataList.get(i).getIc());
|
|
|
- //电流不平衡
|
|
|
+ // 电流不平衡
|
|
|
Double ElBalun = checkBalun(checkList);
|
|
|
if (ElBalun < 0.15) {
|
|
|
OverrunElBalun++;
|
|
@@ -1416,7 +1449,7 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
checkList.add(RtAnalogDataList.get(i).getUa());
|
|
|
checkList.add(RtAnalogDataList.get(i).getUb());
|
|
|
checkList.add(RtAnalogDataList.get(i).getUc());
|
|
|
- //电压不平衡
|
|
|
+ // 电压不平衡
|
|
|
Double VtBalunQ = checkBalun(checkList);
|
|
|
if (VtBalunQ < 0.15) {
|
|
|
OverrunVtBalun++;
|
|
@@ -1466,4 +1499,1534 @@ public class HtAnalogDataServiceImpl extends AbstractCrudService<HtAnalogDataMap
|
|
|
return Arith.div(Arith.sub(max, min), max);
|
|
|
}
|
|
|
|
|
|
+ // 获取设备三相总有功功率值
|
|
|
+ @Override
|
|
|
+ public List<HtAnalogData> getP(List<String> deviceCodes) {
|
|
|
+ return htAnalogDataMapper.getP(deviceCodes);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 总能耗计算
|
|
|
+ *
|
|
|
+ * @param siteId 站点ID
|
|
|
+ * @param time 时间
|
|
|
+ * @param timeType 时间类型 默认: overview 概览,day 日,month 月,year 年
|
|
|
+ * @return HtAnalogEnergyConsumptionVo
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public HtAnalogEnergyConsumptionVo getEnergyConsumption(Integer siteId, Integer consume, LocalDateTime time, String timeType) {
|
|
|
+ if (siteId == null || siteId <= 0) {
|
|
|
+ throw new BusinessException("站点ID异常,请检查后再试");
|
|
|
+ }
|
|
|
+ HtAnalogEnergyConsumptionVo vo = new HtAnalogEnergyConsumptionVo();
|
|
|
+ List<Device> devices = getDevices(siteId);
|
|
|
+ if (devices.isEmpty()) {
|
|
|
+ log.info("站点{}无设备", siteId);
|
|
|
+ return new HtAnalogEnergyConsumptionVo();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 上个月的同一天
|
|
|
+ LocalDate today = time.toLocalDate();
|
|
|
+ LocalDate yesterday1 = today.minusDays(1);
|
|
|
+ LocalDate lastMonth = today.minusMonths(1);
|
|
|
+ LocalDate lastYear = today.minusYears(1);
|
|
|
+
|
|
|
+ List<String> data183 = new ArrayList<>();
|
|
|
+ List<HtAnalogData> dayList = new ArrayList<>();
|
|
|
+ List<HtAnalogData> monthList = new ArrayList<>();
|
|
|
+ List<HtAnalogData> yearList = new ArrayList<>();
|
|
|
+ List<HtAnalogData> yesterday = new ArrayList<>();
|
|
|
+ List<HtAnalogData> sameDayLastMonthList = new ArrayList<>();
|
|
|
+ List<HtAnalogData> sameDayLastYearList = new ArrayList<>();
|
|
|
+
|
|
|
+ List<String> data173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> dayList173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> monthList173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> yearList173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> yesterday173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> sameDayLastMonthList173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> sameDayLastYearList173 = new ArrayList<>();
|
|
|
+
|
|
|
+ for (Device device : devices) {
|
|
|
+ String deviceType = device.getDeviceType();
|
|
|
+ String deviceCode = device.getDeviceCode();
|
|
|
+ if ("1".equals(deviceType)) {
|
|
|
+ data183.add(deviceCode);
|
|
|
+ } else if ("4".equals(deviceType)) {
|
|
|
+ data173.add(deviceCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询站点能耗转换情况(等价 or 当量)
|
|
|
+ SiteDynamicProperties siteDynamicProperties = siteDynamicPropertiesService.selectOne(siteId);
|
|
|
+ if (siteDynamicProperties == null) {
|
|
|
+ log.info("站点{}未配置能耗属性等数据", siteId);
|
|
|
+ return new HtAnalogEnergyConsumptionVo();
|
|
|
+ }
|
|
|
+ Integer demolitionStandardCoal = siteDynamicProperties.getDemolitionStandardCoal();
|
|
|
+ BigDecimal coefficient = new BigDecimal(siteDynamicProperties.getDemolitionStandardCoal1())
|
|
|
+ .divide(new BigDecimal(demolitionStandardCoal), 10, RoundingMode.DOWN);
|
|
|
+
|
|
|
+ // 时间范围
|
|
|
+ TimeRangeUtils.TimeRanges ranges = TimeRangeUtils.getAllTimeRanges(time);
|
|
|
+
|
|
|
+ switch (timeType) {
|
|
|
+ // 概览
|
|
|
+ case "overview":
|
|
|
+ if (!data183.isEmpty()) {
|
|
|
+ String deviceCode183 = data183.get(0);
|
|
|
+ if (consume == 1) {
|
|
|
+ Map<String, BigDecimal> result = analogCache.get(deviceCode183, ranges);
|
|
|
+ BigDecimal today1 = result.get("today");
|
|
|
+ BigDecimal month1 = result.get("month");
|
|
|
+ BigDecimal year1 = result.get("year");
|
|
|
+ BigDecimal yesterday2 = result.get("yesterday");
|
|
|
+ BigDecimal lastMonth1 = result.get("last_month");
|
|
|
+ BigDecimal lastYear1 = result.get("last_year");
|
|
|
+ BigDecimal sameDay = result.get("same_day");
|
|
|
+ BigDecimal sameMonth = result.get("same_month");
|
|
|
+ BigDecimal sameYear = result.get("same_year");
|
|
|
+ BigDecimal lastYearSameDay = result.get("last_year_same_day");
|
|
|
+ BigDecimal lastYearSameMonth = result.get("last_year_same_month");
|
|
|
+
|
|
|
+ // 电
|
|
|
+ vo.setTodayElectricity(today1);
|
|
|
+ vo.setMonthElectricity(month1);
|
|
|
+ vo.setYearElectricity(year1);
|
|
|
+ vo.setYesterdayElectricity(yesterday2);
|
|
|
+ vo.setLastMonthElectricity(lastMonth1);
|
|
|
+ vo.setLastYearElectricity(lastYear1);
|
|
|
+
|
|
|
+ // 环比
|
|
|
+ vo.setTodayRingRatio(ringRatio(today1, sameDay));
|
|
|
+ vo.setMonthRingRatio(ringRatio(month1, sameMonth));
|
|
|
+ vo.setYearRingRatio(ringRatio(year1, sameYear));
|
|
|
+
|
|
|
+ // 能耗
|
|
|
+ vo.setToday(scale(today1, coefficient));
|
|
|
+ vo.setMonth(scale(month1, coefficient));
|
|
|
+ vo.setYear(scale(year1, coefficient));
|
|
|
+ vo.setYesterday(scale(yesterday2, coefficient));
|
|
|
+ vo.setLastMonth(scale(lastMonth1, coefficient));
|
|
|
+ vo.setLastYear(scale(lastYear1, coefficient));
|
|
|
+ } else if (consume == 2) {
|
|
|
+ // 1. 计算电量 & 基础费用
|
|
|
+ // ElectricityRateConfig cfg = getElectricityRateConfig(siteId);
|
|
|
+
|
|
|
+ // BigDecimal dayElectricity = getTotal(dayList);
|
|
|
+ // BigDecimal monthElectricity = getTotal(monthList);
|
|
|
+ // BigDecimal yearElectricity = getTotal(yearList);
|
|
|
+ // BigDecimal sameDayElectricity = getTotal(yesterday);
|
|
|
+ // BigDecimal sameMonthElectricity = getTotal(sameDayLastMonthList);
|
|
|
+ // BigDecimal sameYearElectricity = getTotal(sameDayLastYearList);
|
|
|
+
|
|
|
+ // 基本费用
|
|
|
+ // BigDecimal dayBasic = getBasicExpenses(dayList, cfg, siteId, dayElectricity);
|
|
|
+ // BigDecimal monthBasic = getBasicExpenses(monthList, cfg, siteId, monthElectricity);
|
|
|
+ // BigDecimal yearBasic = getBasicExpenses(yearList, cfg, siteId, yearElectricity);
|
|
|
+ // BigDecimal sameDayBasic = getBasicExpenses(yesterday, cfg, siteId, sameDayElectricity);
|
|
|
+ // BigDecimal sameMonthBasic = getBasicExpenses(sameDayLastMonthList, cfg, siteId, sameMonthElectricity);
|
|
|
+ // BigDecimal sameYearBasic = getBasicExpenses(sameDayLastYearList, cfg, siteId, sameYearElectricity);
|
|
|
+
|
|
|
+ // 3. 费用汇总
|
|
|
+ BigDecimal dayCost = siteFeeCacheService.getTotalCost(siteId, ranges.getToday(), 1);//.add(dayBasic);
|
|
|
+ BigDecimal monthCost = siteFeeCacheService.getTotalCost(siteId, ranges.getToday(), 2);
|
|
|
+ BigDecimal yearCost = siteFeeCacheService.getTotalCost(siteId, ranges.getToday(), 3);
|
|
|
+
|
|
|
+ BigDecimal yesterdayCost = siteFeeCacheService.getTotalCost(siteId, ranges.getYesterdayRange()[0], 1);//.add(sameDayBasic);
|
|
|
+ BigDecimal sameMonthCost = siteFeeCacheService.getTotalCost(siteId, ranges.getSameMonthRange()[1].toLocalDate(), 22);
|
|
|
+ BigDecimal sameYearCost = siteFeeCacheService.getTotalCost(siteId, ranges.getSameYearRange()[1].toLocalDate(), 33);
|
|
|
+
|
|
|
+ // 4. 设置值
|
|
|
+ vo.setTodayCost(dayCost);
|
|
|
+ vo.setMonthCost(monthCost);
|
|
|
+ vo.setYearCost(yearCost);
|
|
|
+ vo.setYesterdayCost(yesterdayCost);
|
|
|
+ vo.setLastMonthCost(sameMonthCost);
|
|
|
+ vo.setLastYearCost(sameYearCost);
|
|
|
+
|
|
|
+ // 日环比
|
|
|
+ vo.setDayCostRingRatio(ringRatio(dayCost, yesterdayCost));
|
|
|
+ // 月环比
|
|
|
+ vo.setMonthCostRingRatio(ringRatio(monthCost, sameMonthCost));
|
|
|
+ // 年环比
|
|
|
+ vo.setYearCostRingRatio(ringRatio(yearCost, sameYearCost));
|
|
|
+ }
|
|
|
+ } else if (!data173.isEmpty()) {
|
|
|
+ dayList173 = get173Data(data173, time, 1);
|
|
|
+ monthList173 = get173Data(data173, time, 2);
|
|
|
+ yearList173 = get173Data(data173, time, 3);
|
|
|
+
|
|
|
+ yesterday173 = get173Data(data173, time.minusDays(1), 1);
|
|
|
+ sameDayLastMonthList173 = get173Data(data173, time.minusDays(1), 2);
|
|
|
+ sameDayLastYearList173 = get173Data(data173, time.minusDays(1), 3);
|
|
|
+
|
|
|
+ if (consume == 1) {
|
|
|
+ // 电耗
|
|
|
+ vo.setTodayElectricity(get173Total(dayList173));
|
|
|
+ vo.setMonthElectricity(get173Total(monthList173));
|
|
|
+ vo.setYearElectricity(get173Total(yearList173));
|
|
|
+ vo.setYesterdayElectricity(get173Total(yesterday173));
|
|
|
+ vo.setLastMonthElectricity(get173Total(sameDayLastMonthList173));
|
|
|
+ vo.setLastYearElectricity(get173Total(sameDayLastYearList173));
|
|
|
+
|
|
|
+ // 能耗
|
|
|
+ vo.setToday(get173Total(dayList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setMonth(get173Total(monthList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setYear(get173Total(yearList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setYesterday(get173Total(yesterday173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setLastMonth(get173Total(sameDayLastMonthList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setLastYear(get173Total(sameDayLastYearList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+
|
|
|
+ // 电耗环比
|
|
|
+ vo.setTodayRingRatio(calcMoM(time, dayList173, yearList173));
|
|
|
+ vo.setMonthRingRatio(calcMoM(time, monthList173, sameDayLastMonthList173));
|
|
|
+ vo.setYearRingRatio(calcMoM(time, yearList173, sameDayLastYearList173));
|
|
|
+ } else if (consume == 2) {
|
|
|
+
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return new HtAnalogEnergyConsumptionVo();
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ // 日
|
|
|
+ case "day":
|
|
|
+ if (consume == 1) {
|
|
|
+ if (!data183.isEmpty()) {
|
|
|
+ dayList = getAnalogData(data183.get(0), time, 1);
|
|
|
+ // 此处为昨日同期电耗
|
|
|
+ yesterday = getAnalogData(data183.get(0), time.minusDays(1), 11);
|
|
|
+
|
|
|
+ // 电耗
|
|
|
+ vo.setTodayElectricity(getTotal(dayList));
|
|
|
+ // 昨日同期电耗
|
|
|
+ // vo.setYesterdayElectricity(getTotal(yesterday));
|
|
|
+ BigDecimal yesterdaySameTimeElectricity = getTotal(yesterday);
|
|
|
+ // 能耗
|
|
|
+ vo.setToday(scale(vo.getTodayElectricity(), coefficient));
|
|
|
+ vo.setYesterday(scale(yesterdaySameTimeElectricity, coefficient));
|
|
|
+ // 日同期环比
|
|
|
+ vo.setTodayRingRatio(ringRatio(vo.getTodayElectricity(), yesterdaySameTimeElectricity));
|
|
|
+
|
|
|
+ // 上一年同日能耗
|
|
|
+ List<HtAnalogData> analogData = getAnalogData(data183.get(0), time.minusYears(1), 1);
|
|
|
+ BigDecimal sameDayLastYearEnergy = scale(getTotal(analogData), coefficient);
|
|
|
+ vo.setYearOnYear(sameDayLastYearEnergy);
|
|
|
+ // 日能耗同比
|
|
|
+ vo.setYearOnYearPercent(ringRatio(vo.getToday(), sameDayLastYearEnergy));
|
|
|
+ } else if (!data173.isEmpty()) {
|
|
|
+ dayList173 = get173Data(data173, time, 1);
|
|
|
+ yesterday173 = get173Data(data173, time.minusDays(1), 1);
|
|
|
+
|
|
|
+ // 电耗
|
|
|
+ vo.setTodayElectricity(get173Total(dayList173));
|
|
|
+ vo.setYesterdayElectricity(get173Total(yesterday173));
|
|
|
+ // 能耗
|
|
|
+ vo.setToday(get173Total(dayList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ // 昨日同期能耗
|
|
|
+ vo.setYesterday(get173Total(yesterday173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+
|
|
|
+ // 上一年同日能耗
|
|
|
+ List<HtAnalog173Data> analogData = get173Data(data173, time.minusYears(1), 1);
|
|
|
+ BigDecimal sameDayLastYearEnergy = get173Total(analogData).multiply(coefficient).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ vo.setYearOnYear(sameDayLastYearEnergy);
|
|
|
+ // 日能耗同比
|
|
|
+ vo.setYearOnYearPercent(get173Total(dayList173).multiply(coefficient).divide(sameDayLastYearEnergy, 2, RoundingMode.HALF_UP));
|
|
|
+ }
|
|
|
+ } else if (consume == 2) {
|
|
|
+ ElectricityRateConfig cfg = getElectricityRateConfig(siteId);
|
|
|
+ if (!data183.isEmpty()) {
|
|
|
+ dayList = getAnalogData(data183.get(0), time, 1);
|
|
|
+ vo.setTodayElectricity(getTotal(dayList));
|
|
|
+
|
|
|
+ dayList = getAnalogData(data183.get(0), time, 1);
|
|
|
+ yesterday = getAnalogData(data183.get(0), ranges.getYesterdayTime(), 1);
|
|
|
+
|
|
|
+ BigDecimal dayElectricity = getTotal(dayList);
|
|
|
+ BigDecimal sameDayElectricity = getTotal(yesterday);
|
|
|
+ BigDecimal dayBasic = getBasicExpenses(dayList, cfg, siteId, dayElectricity);
|
|
|
+ BigDecimal sameDayBasic = getBasicExpenses(yesterday, cfg, siteId, sameDayElectricity);
|
|
|
+ BigDecimal dayCost = calculateTotalCost(calculateTimeFee(siteId, today, 1)).add(dayBasic);
|
|
|
+ BigDecimal yesterdayCost = calculateTotalCost(calculateTimeFee(siteId, yesterday1, 1)).add(sameDayBasic);
|
|
|
+ vo.setTodayCost(dayCost);
|
|
|
+ vo.setYesterdayCost(yesterdayCost);
|
|
|
+ vo.setDayCostRingRatio(ringRatio(dayCost, yesterdayCost));
|
|
|
+
|
|
|
+ // 上一年同日能耗
|
|
|
+ List<HtAnalogData> sameDayLastYear = getAnalogData(data183.get(0), ranges.getLastYearSameDay()[0], 1);
|
|
|
+ BigDecimal sameDayLastYearElectricity = getTotal(sameDayLastYear);
|
|
|
+ BigDecimal sameDayLastYearBasic = getBasicExpenses(sameDayLastYear, cfg, siteId, sameDayLastYearElectricity);
|
|
|
+ BigDecimal sameDayLastYearCost = calculateTotalCost(calculateTimeFee(siteId, lastYear, 1)).add(sameDayLastYearBasic);
|
|
|
+ vo.setYearOnYear(sameDayLastYearCost);
|
|
|
+ vo.setYearOnYearPercent(ringRatio(dayCost, sameDayLastYearCost));
|
|
|
+
|
|
|
+ } else if (!data173.isEmpty()) {
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ // 月
|
|
|
+ case "month":
|
|
|
+ if (!data183.isEmpty()) {
|
|
|
+ String deviceCode183 = data183.get(0);
|
|
|
+ Map<String, BigDecimal> result = analogCache.get(deviceCode183, ranges);
|
|
|
+ BigDecimal month1 = result.get("month");
|
|
|
+ // 电耗
|
|
|
+ vo.setMonthElectricity(month1);
|
|
|
+ // monthList = getAnalogData(deviceCode183, time, 2);
|
|
|
+ // sameDayLastMonthList = getAnalogData(deviceCode183, time.minusMonths(1), 22);
|
|
|
+ // 上一年同月能耗
|
|
|
+ // List<HtAnalogData> analogData = getAnalogData(deviceCode183, time.minusYears(1), 2);
|
|
|
+ if (consume == 1) {
|
|
|
+ BigDecimal sameMonth = result.get("same_month");
|
|
|
+ BigDecimal lastYearSameMonth = result.get("last_year_same_month");
|
|
|
+ // 上月同期电耗
|
|
|
+ vo.setLastMonthElectricity(sameMonth);
|
|
|
+ // 能耗
|
|
|
+ vo.setMonth(scale(month1, coefficient));
|
|
|
+ vo.setLastMonth(scale(sameMonth, coefficient));
|
|
|
+ // 同期环比
|
|
|
+ vo.setMonthRingRatio(ringRatio(month1, sameMonth));
|
|
|
+
|
|
|
+ // BigDecimal sameMonthLastYearEnergy = getTotal(analogData).multiply(coefficient).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ vo.setYearOnYear(lastYearSameMonth);
|
|
|
+ // 月能耗同比
|
|
|
+ vo.setYearOnYearPercent(ringRatio(month1, lastYearSameMonth));
|
|
|
+ } else if (consume == 2) {
|
|
|
+ // vo.setMonthElectricity(getTotal(monthList));
|
|
|
+
|
|
|
+ BigDecimal monthCost = siteFeeCacheService.getTotalCost(siteId, ranges.getToday(), 2);
|
|
|
+ BigDecimal sameMonthCost = siteFeeCacheService.getTotalCost(siteId, ranges.getSameMonthRange()[0].toLocalDate(), 22);
|
|
|
+ BigDecimal sameMonthLastYearCost = siteFeeCacheService.getTotalCost(siteId, ranges.getLastYearSameMonth()[0].toLocalDate(), 4);
|
|
|
+
|
|
|
+ // ElectricityRateConfig cfg = getElectricityRateConfig(siteId);
|
|
|
+ // BigDecimal monthBasic = getBasicExpenses(monthList, cfg, siteId, getTotal(monthList));
|
|
|
+ // BigDecimal sameMonthBasic = getBasicExpenses(sameDayLastMonthList, cfg, siteId, getTotal(sameDayLastMonthList));
|
|
|
+ // BigDecimal monthCost = calculateTotalCost(calculateTimeFee(siteId, today, 2)).add(monthBasic);
|
|
|
+ // BigDecimal sameMonthCost = calculateTotalCost(calculateTimeFee(siteId, lastMonth, 22)).add(sameMonthBasic);
|
|
|
+ vo.setMonthCost(monthCost);
|
|
|
+ // 上月同期费用
|
|
|
+ vo.setLastMonthCost(sameMonthCost);
|
|
|
+ vo.setMonthCostRingRatio(ringRatio(monthCost, sameMonthCost));
|
|
|
+ // 上一年同月能耗
|
|
|
+ // List<HtAnalogData> sameMonthLastYear = getAnalogData(deviceCode183, time.minusYears(1), 2);
|
|
|
+ // BigDecimal sameMonthLastYearElectricity = getTotal(sameMonthLastYear);
|
|
|
+ // BigDecimal sameMonthLastYearBasic = getBasicExpenses(sameMonthLastYear, cfg, siteId, sameMonthLastYearElectricity);
|
|
|
+ // BigDecimal sameMonthLastYearCost = calculateTotalCost(calculateTimeFee(siteId, lastMonth, 2)).add(sameMonthLastYearBasic);
|
|
|
+ vo.setYearOnYear(sameMonthLastYearCost);
|
|
|
+ vo.setYearOnYearPercent(ringRatio(monthCost, sameMonthLastYearCost));
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (!data173.isEmpty()) {
|
|
|
+ monthList173 = get173Data(data173, time, 2);
|
|
|
+ sameDayLastMonthList173 = get173Data(data173, time.minusMonths(1), 2);
|
|
|
+
|
|
|
+ // 电耗
|
|
|
+ vo.setMonthElectricity(get173Total(monthList173));
|
|
|
+ vo.setLastMonthElectricity(get173Total(sameDayLastMonthList173));
|
|
|
+ // 能耗
|
|
|
+ vo.setMonth(get173Total(monthList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setLastMonth(get173Total(sameDayLastMonthList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ // 月同期环比
|
|
|
+ vo.setMonthRingRatio(calcMoM(time, monthList173, sameDayLastMonthList173));
|
|
|
+
|
|
|
+ // 上一年同月能耗
|
|
|
+ List<HtAnalog173Data> analogData = get173Data(data173, time.minusYears(1), 2);
|
|
|
+ BigDecimal sameMonthLastYearEnergy = get173Total(analogData).multiply(coefficient).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ vo.setYearOnYear(sameMonthLastYearEnergy);
|
|
|
+ // 月能耗同比
|
|
|
+ vo.setYearOnYearPercent(get173Total(monthList173).multiply(coefficient).divide(sameMonthLastYearEnergy, 3, RoundingMode.HALF_UP));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ // 年
|
|
|
+ case "year":
|
|
|
+ if (!data183.isEmpty()) {
|
|
|
+ String deviceCode183 = data183.get(0);
|
|
|
+ Map<String, BigDecimal> result = analogCache.get(deviceCode183, ranges);
|
|
|
+ BigDecimal year1 = result.get("year");
|
|
|
+ // yearList = getAnalogData(deviceCode183, time, 3);
|
|
|
+ // sameDayLastYearList = getAnalogData(deviceCode183, time.minusYears(1), 33);
|
|
|
+
|
|
|
+ if (consume == 1) {
|
|
|
+ BigDecimal sameYear = result.get("same_year");
|
|
|
+ // 电耗
|
|
|
+ vo.setYearElectricity(year1);
|
|
|
+ // 去年同期电耗
|
|
|
+ vo.setLastYearElectricity(sameYear);
|
|
|
+ // 能耗
|
|
|
+ vo.setYear(scale(year1, coefficient));
|
|
|
+ vo.setLastYear(scale(sameYear, coefficient));
|
|
|
+ // 环比
|
|
|
+ vo.setYearRingRatio(ringRatio(year1, sameYear));
|
|
|
+ // 同比
|
|
|
+ vo.setYearOnYear(vo.getYear());
|
|
|
+ vo.setYearOnYearPercent(vo.getYearCostRingRatio());
|
|
|
+ // 上一年能耗
|
|
|
+ // List<HtAnalogData> analogData = getAnalogData(deviceCode183, time.minusYears(1), 3);
|
|
|
+ // vo.setYearOnYear(getTotal(analogData).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ } else if (consume == 2) {
|
|
|
+ // vo.setYearElectricity(getTotal(yearList));
|
|
|
+
|
|
|
+ BigDecimal yearCost = siteFeeCacheService.getTotalCost(siteId, ranges.getToday(), 3);
|
|
|
+
|
|
|
+ BigDecimal sameYearCost = siteFeeCacheService.getTotalCost(siteId, ranges.getSameYearRange()[1].toLocalDate(), 33);
|
|
|
+
|
|
|
+ // ElectricityRateConfig cfg = getElectricityRateConfig(siteId);
|
|
|
+ // BigDecimal yearBasic = getBasicExpenses(yearList, cfg, siteId, getTotal(yearList));
|
|
|
+ // BigDecimal sameYearBasic = getBasicExpenses(sameDayLastYearList, cfg, siteId, getTotal(sameDayLastYearList));
|
|
|
+ // BigDecimal yearCost = calculateTotalCost(calculateTimeFee(siteId, today, 3)).add(yearBasic);
|
|
|
+ // BigDecimal sameYearCost = calculateTotalCost(calculateTimeFee(siteId, lastYear, 33)).add(sameYearBasic);
|
|
|
+ vo.setYearCost(yearCost);
|
|
|
+ vo.setLastYearCost(sameYearCost);
|
|
|
+ vo.setYearCostRingRatio(ringRatio(yearCost, sameYearCost));
|
|
|
+ vo.setYearOnYear(sameYearCost);
|
|
|
+ vo.setYearOnYearPercent(vo.getYearCostRingRatio());
|
|
|
+ }
|
|
|
+ } else if (!data173.isEmpty()) {
|
|
|
+ yearList173 = get173Data(data173, time, 3);
|
|
|
+ sameDayLastYearList173 = get173Data(data173, time.minusYears(1), 3);
|
|
|
+
|
|
|
+ // 电耗
|
|
|
+ vo.setYearElectricity(get173Total(yearList173));
|
|
|
+ vo.setLastYearElectricity(get173Total(sameDayLastYearList173));
|
|
|
+ // 能耗
|
|
|
+ vo.setYear(get173Total(yearList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setLastYear(get173Total(sameDayLastYearList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ // 环比
|
|
|
+ vo.setYearRingRatio(calcMoM(time, yearList173, sameDayLastYearList173));
|
|
|
+ // 同比
|
|
|
+ vo.setYearOnYear(get173Total(sameDayLastYearList173).multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setYearOnYearPercent(calcMoM(time, yearList173, sameDayLastYearList173));
|
|
|
+
|
|
|
+ // 上一年总能耗
|
|
|
+ // List<HtAnalog173Data> analogData = get173Data(data173, time.minusYears(1), 3);
|
|
|
+ // BigDecimal sameYearLastYearEnergy = get173Total(analogData).multiply(coefficient).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 环比计算
|
|
|
+ public static BigDecimal ringRatio(BigDecimal value, BigDecimal same) {
|
|
|
+ return same.compareTo(ZERO) == 0 ? ZERO : value.subtract(same).divide(same, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 能耗转换
|
|
|
+ public static BigDecimal scale(BigDecimal value, BigDecimal coefficient) {
|
|
|
+ return value == null ? ZERO : value.multiply(coefficient).setScale(3, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取173数据
|
|
|
+ public List<HtAnalog173Data> get173Data(List<String> deviceCodeList, LocalDateTime localDateTime, int timeType) {
|
|
|
+ LocalDate data = localDateTime.toLocalDate();
|
|
|
+ LocalDate monthFirstDay = data.with(TemporalAdjusters.firstDayOfMonth());
|
|
|
+ LocalDate monthLastDay = data.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ LocalDate yearFirstDay = data.with(TemporalAdjusters.firstDayOfYear());
|
|
|
+ LocalDate yearLastDay = data.with(TemporalAdjusters.lastDayOfYear());
|
|
|
+ LocalDateTime dayFirstTime = LocalDateTime.of(data, LocalTime.MIN);
|
|
|
+
|
|
|
+ LambdaQueryWrapper<HtAnalog173Data> queryWrapper = Wrappers.lambdaQuery();
|
|
|
+ queryWrapper.in(HtAnalog173Data::getDeviceName, deviceCodeList);
|
|
|
+
|
|
|
+ switch (timeType) {
|
|
|
+ // 日
|
|
|
+ case 1:
|
|
|
+ queryWrapper.eq(HtAnalog173Data::getFreezingTime, data);
|
|
|
+ break;
|
|
|
+ // 月
|
|
|
+ case 2:
|
|
|
+ queryWrapper.between(HtAnalog173Data::getFreezingTime, monthFirstDay, monthLastDay);
|
|
|
+ break;
|
|
|
+ // 年
|
|
|
+ case 3:
|
|
|
+ queryWrapper.between(HtAnalog173Data::getFreezingTime, yearFirstDay, yearLastDay);
|
|
|
+ break;
|
|
|
+
|
|
|
+ // 同期
|
|
|
+ case 11:
|
|
|
+ queryWrapper.between(HtAnalog173Data::getDataTime, dayFirstTime, localDateTime);
|
|
|
+ break;
|
|
|
+ case 22:
|
|
|
+ queryWrapper.between(HtAnalog173Data::getFreezingTime, monthFirstDay, data);
|
|
|
+ break;
|
|
|
+ case 33:
|
|
|
+ queryWrapper.between(HtAnalog173Data::getFreezingTime, yearFirstDay, data);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ log.error("173无效的时间类型: " + timeType);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+
|
|
|
+ queryWrapper.select(HtAnalog173Data::getDeviceName,
|
|
|
+ HtAnalog173Data::getFreezingTime,
|
|
|
+ HtAnalog173Data::getEpp,
|
|
|
+ HtAnalog173Data::getDataTime)
|
|
|
+ .orderByDesc(HtAnalog173Data::getDataTime);
|
|
|
+
|
|
|
+ return htAnalog173DataMapper.selectList(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取173数据总量
|
|
|
+ */
|
|
|
+ public BigDecimal get173Total(List<HtAnalog173Data> dataList) {
|
|
|
+ if (CollectionUtils.isEmpty(dataList)) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+ return dataList.stream()
|
|
|
+ .collect(Collectors.groupingBy(HtAnalog173Data::getDeviceName))
|
|
|
+ .values()
|
|
|
+ .stream()
|
|
|
+ .map(list -> list.stream()
|
|
|
+ .sorted(Comparator.comparing(HtAnalog173Data::getDataTime))
|
|
|
+ .map(HtAnalog173Data::getEpp)
|
|
|
+ .reduce((first, last) -> last.subtract(first))
|
|
|
+ .orElse(ZERO))
|
|
|
+ .reduce(ZERO, BigDecimal::add);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算环比
|
|
|
+ * @param localDateTime 基准时间(含)
|
|
|
+ * @param dayList173 日数据集合
|
|
|
+ * @param yearList173 年数据集合
|
|
|
+ * @return 环比值,已四舍五入到小数点后两位
|
|
|
+ */
|
|
|
+ public BigDecimal calcMoM(LocalDateTime localDateTime,
|
|
|
+ List<HtAnalog173Data> dayList173,
|
|
|
+ List<HtAnalog173Data> yearList173) {
|
|
|
+
|
|
|
+ BigDecimal daySum = calcDeviceDiffSum(dayList173, localDateTime);
|
|
|
+ BigDecimal yearSum = calcDeviceDiffSum(yearList173, localDateTime);
|
|
|
+
|
|
|
+ if (yearSum.compareTo(ZERO) == 0) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return daySum
|
|
|
+ // 先多保留几位,避免中间精度损失
|
|
|
+ .divide(yearSum, 4, RoundingMode.HALF_UP)
|
|
|
+ .setScale(3, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通用内部方法:对给定集合按设备分组,并计算每台设备
|
|
|
+ * “localDateTime 之前”最后一条 epp - 第一条 epp 的差值总和
|
|
|
+ */
|
|
|
+ private BigDecimal calcDeviceDiffSum(List<HtAnalog173Data> list,
|
|
|
+ LocalDateTime localDateTime) {
|
|
|
+
|
|
|
+ if (CollectionUtils.isEmpty(list)) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return list.stream()
|
|
|
+ .filter(d -> !d.getDataTime().isAfter(localDateTime))
|
|
|
+ .collect(Collectors.groupingBy(HtAnalog173Data::getDeviceName))
|
|
|
+ .values()
|
|
|
+ .stream()
|
|
|
+ .map(deviceList -> deviceList.stream()
|
|
|
+ .sorted(Comparator.comparing(HtAnalog173Data::getDataTime))
|
|
|
+ .map(HtAnalog173Data::getEpp)
|
|
|
+ .reduce((first, last) -> last.subtract(first))
|
|
|
+ .orElse(ZERO))
|
|
|
+ .reduce(ZERO, BigDecimal::add);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算指定时期内的数据总量
|
|
|
+ */
|
|
|
+ public BigDecimal getTotal(List<HtAnalogData> dataList) {
|
|
|
+ if (dataList == null || dataList.isEmpty()) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取最大最小时间,已按照时间顺序倒序
|
|
|
+ HtAnalogData max = dataList.get(0), min = dataList.get(dataList.size() - 1);
|
|
|
+ // for (int i = 1, size = dataList.size(); i < size; i++) {
|
|
|
+ // HtAnalogData d = dataList.get(i);
|
|
|
+ // if (d.getDataTime().isAfter(max.getDataTime())) {
|
|
|
+ // max = d;
|
|
|
+ // }
|
|
|
+ // if (d.getDataTime().isBefore(min.getDataTime())) {
|
|
|
+ // min = d;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ if (max.getEpp() == null || min.getEpp() == null ||
|
|
|
+ max.getEpp().compareTo(min.getEpp()) == 0 || min.getEpp().compareTo(ZERO) == 0) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+ return max.getEpp().subtract(min.getEpp());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取站点下的设备
|
|
|
+ */
|
|
|
+ private List<Device> getDevices(Integer siteId) {
|
|
|
+ LambdaQueryWrapper<Device> queryWrapper = Wrappers.lambdaQuery();
|
|
|
+ queryWrapper.eq(Device::getSiteId, siteId)
|
|
|
+ .eq(Device::getEnable, 1)
|
|
|
+ .select(Device::getDeviceCode, Device::getDeviceType);
|
|
|
+ return deviceMapper.selectList(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取设备三相有功功率值
|
|
|
+ * @param deviceCode 设备编码
|
|
|
+ * @param localDateTime 日期
|
|
|
+ * @param timeType 时间类型 日月年 123 日月年同期 11 22 33
|
|
|
+ * @return 设备三相有功功率值
|
|
|
+ */
|
|
|
+ public List<HtAnalogData> getAnalogData(String deviceCode, LocalDateTime localDateTime, int timeType) {
|
|
|
+ LocalDate data = localDateTime.toLocalDate();
|
|
|
+ LambdaQueryWrapper<HtAnalogData> queryWrapper = Wrappers.lambdaQuery();
|
|
|
+ queryWrapper.select(HtAnalogData::getDeviceName,
|
|
|
+ HtAnalogData::getFreezingTime,
|
|
|
+ HtAnalogData::getEpp,
|
|
|
+ HtAnalogData::getDataTime);
|
|
|
+ queryWrapper.eq(HtAnalogData::getDeviceName, deviceCode);
|
|
|
+ switch (timeType) {
|
|
|
+ // 日
|
|
|
+ case 1:
|
|
|
+ queryWrapper.eq(HtAnalogData::getFreezingTime, data);
|
|
|
+ break;
|
|
|
+ // 月
|
|
|
+ case 2:
|
|
|
+ LocalDate monthFirstDay = data.with(TemporalAdjusters.firstDayOfMonth());
|
|
|
+ LocalDate monthMonthLastDay = data.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ queryWrapper.between(HtAnalogData::getFreezingTime, monthFirstDay, monthMonthLastDay);
|
|
|
+ break;
|
|
|
+ // 年
|
|
|
+ case 3:
|
|
|
+ LocalDate yearFirstDay = data.with(TemporalAdjusters.firstDayOfYear());
|
|
|
+ LocalDate yearLastDay = data.with(TemporalAdjusters.lastDayOfYear());
|
|
|
+ queryWrapper.between(HtAnalogData::getFreezingTime, yearFirstDay, yearLastDay);
|
|
|
+ break;
|
|
|
+
|
|
|
+ // 昨日同期
|
|
|
+ case 11:
|
|
|
+ LocalDateTime dayFirstTime = LocalDateTime.of(data, LocalTime.MIN);
|
|
|
+ queryWrapper.between(HtAnalogData::getDataTime, dayFirstTime.minusDays(1), localDateTime.minusDays(1));
|
|
|
+ break;
|
|
|
+ // 上月同期
|
|
|
+ case 22:
|
|
|
+ LocalDateTime monthFirstTime = localDateTime.with(TemporalAdjusters.firstDayOfMonth());
|
|
|
+ queryWrapper.between(HtAnalogData::getDataTime, monthFirstTime.minusMonths(1), localDateTime.minusMonths(1));
|
|
|
+ break;
|
|
|
+ // 上年同期
|
|
|
+ case 33:
|
|
|
+ LocalDateTime yearFirstTime = localDateTime.with(TemporalAdjusters.firstDayOfYear());
|
|
|
+ queryWrapper.between(HtAnalogData::getDataTime, yearFirstTime.minusYears(1), localDateTime.minusYears(1));
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ log.error("183无效的时间类型: " + timeType);
|
|
|
+ return Collections.emptyList();
|
|
|
+ }
|
|
|
+ queryWrapper.orderByDesc(HtAnalogData::getDataTime);
|
|
|
+ return htAnalogDataMapper.selectList(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 获取差值列表
|
|
|
+// *
|
|
|
+// * @param timeType 时间类型
|
|
|
+// * @param timeList 时间列表
|
|
|
+// * @return 时间值列表
|
|
|
+// */
|
|
|
+// public List<BigDecimal> getTimeValues(List<HtAnalogData> source,
|
|
|
+// Integer timeType,
|
|
|
+// List<String> timeList) {
|
|
|
+//
|
|
|
+// if (source == null || source.isEmpty() || timeList == null || timeList.isEmpty()) {
|
|
|
+// return Collections.nCopies(timeList == null ? 0 : timeList.size(), ZERO);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 提取时间“槽位”的映射函数
|
|
|
+// Function<HtAnalogData, Integer> slotExtractor;
|
|
|
+// switch (timeType) {
|
|
|
+// // 日 -> 小时 0-23
|
|
|
+// case 1:
|
|
|
+// slotExtractor = d -> d.getDataTime().getHour();
|
|
|
+// break;
|
|
|
+// // 月 -> 天 1-31(需与 timeList 的索引对齐)
|
|
|
+// case 2:
|
|
|
+// slotExtractor = d -> d.getDataTime().getDayOfMonth() - 1;
|
|
|
+// break;
|
|
|
+// // 年 -> 月 1-12
|
|
|
+// case 3:
|
|
|
+// slotExtractor = d -> d.getDataTime().getMonthValue() - 1;
|
|
|
+// break;
|
|
|
+// default:
|
|
|
+// throw new IllegalArgumentException("不支持的 timeType: " + timeType);
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 按槽位分组并排序
|
|
|
+// Map<Integer, List<HtAnalogData>> grouped = source.stream()
|
|
|
+// .filter(Objects::nonNull)
|
|
|
+// .sorted(Comparator.comparing(HtAnalogData::getDataTime))
|
|
|
+// .collect(Collectors.groupingBy(slotExtractor));
|
|
|
+//
|
|
|
+// // 构造结果,顺序与 timeList 保持一致
|
|
|
+// List<BigDecimal> result = new ArrayList<>(Collections.nCopies(timeList.size(), ZERO));
|
|
|
+//
|
|
|
+// grouped.forEach((slot, list) -> {
|
|
|
+// if (slot >= 0 && slot < timeList.size() && list.size() >= 2) {
|
|
|
+// BigDecimal first = list.get(0).getEpp();
|
|
|
+// BigDecimal last = list.get(list.size() - 1).getEpp();
|
|
|
+// result.set(slot, last.subtract(first));
|
|
|
+// }
|
|
|
+// });
|
|
|
+//
|
|
|
+// return result;
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取环比
|
|
|
+ *
|
|
|
+ * @param curList 第一个列表
|
|
|
+ * @param preList 第二个列表
|
|
|
+ * @return 环比
|
|
|
+ */
|
|
|
+ public BigDecimal getRingRatio(List<HtAnalogData> curList,
|
|
|
+ List<HtAnalogData> preList) {
|
|
|
+ if (curList.isEmpty() || preList.isEmpty()) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 已倒序:0 是最新,size-1 是最早
|
|
|
+ BigDecimal curDiff = curList.get(0).getEpp()
|
|
|
+ .subtract(curList.get(curList.size() - 1).getEpp());
|
|
|
+ BigDecimal preDiff = preList.get(0).getEpp()
|
|
|
+ .subtract(preList.get(preList.size() - 1).getEpp());
|
|
|
+
|
|
|
+ if (preDiff.compareTo(ZERO) == 0) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算环比:(cur - pre) / pre
|
|
|
+ return curDiff.subtract(preDiff)
|
|
|
+ .divide(preDiff, 3, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+// @Override
|
|
|
+// public HtAnalogEnergySegmentedVo getSegmentedData(Integer siteId, String queryPeriod, LocalDateTime queryTime, String queryType) {
|
|
|
+// HtAnalogEnergySegmentedVo vo = new HtAnalogEnergySegmentedVo();
|
|
|
+// List<String> devices183 = new ArrayList<>();
|
|
|
+// List<String> devices173 = new ArrayList<>();
|
|
|
+//
|
|
|
+// List<HtAnalogData> data183 = new ArrayList<>();
|
|
|
+// List<HtAnalogData> previousData183 = new ArrayList<>();
|
|
|
+// List<HtAnalog173Data> data173 = new ArrayList<>();
|
|
|
+// List<HtAnalog173Data> previousData173 = new ArrayList<>();
|
|
|
+//
|
|
|
+// List<BigDecimal> amountList = new ArrayList<>();
|
|
|
+// List<LocalDateTime> timeKeys = new ArrayList<>();
|
|
|
+//
|
|
|
+// List<Device> devices = getDevices(siteId);
|
|
|
+// if (devices.isEmpty()) {
|
|
|
+// log.warn("站点 {} 无设备!", siteId);
|
|
|
+// return vo;
|
|
|
+// }
|
|
|
+//
|
|
|
+// for (Device device : devices) {
|
|
|
+// String deviceType = device.getDeviceType();
|
|
|
+// String deviceCode = device.getDeviceCode();
|
|
|
+// if ("1".equals(deviceType)) {
|
|
|
+// devices183.add(deviceCode);
|
|
|
+// } else if ("4".equals(deviceType)) {
|
|
|
+// devices173.add(deviceCode);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// switch (queryPeriod) {
|
|
|
+// case "hour":
|
|
|
+// if (!devices183.isEmpty()) {
|
|
|
+// data183 = getAnalogData(devices183.get(0), queryTime, 1);
|
|
|
+// previousData183 = getAnalogData(devices183.get(0), queryTime.minusDays(1), 1);
|
|
|
+//
|
|
|
+// amountList =
|
|
|
+// timeKeys =
|
|
|
+// } else if (!devices173.isEmpty()) {
|
|
|
+// data173 = get173Data(devices173, queryTime, 1);
|
|
|
+// previousData173 = get173Data(devices173, queryTime.minusDays(1), 1);
|
|
|
+//
|
|
|
+// vo.setRatio(getRingRatio(data183, previousData183));
|
|
|
+// }
|
|
|
+// break;
|
|
|
+// case "day":
|
|
|
+// if (!devices183.isEmpty()) {
|
|
|
+// data183 = getAnalogData(devices183.get(0), queryTime, 2);
|
|
|
+// previousData183 = getAnalogData(devices183.get(0), queryTime.minusMonths(1), 2);
|
|
|
+//
|
|
|
+// amountList =
|
|
|
+// timeKeys =
|
|
|
+// } else if (!devices173.isEmpty()) {
|
|
|
+// data173 = get173Data(devices173, queryTime, 2);
|
|
|
+// previousData173 = get173Data(devices173, queryTime.minusMonths(1), 2);
|
|
|
+// }
|
|
|
+// break;
|
|
|
+// case "month":
|
|
|
+// if (!devices183.isEmpty()) {
|
|
|
+// data183 = getAnalogData(devices183.get(0), queryTime, 3);
|
|
|
+// previousData183 = getAnalogData(devices183.get(0), queryTime.minusYears(1), 3);
|
|
|
+// amountList =
|
|
|
+// timeKeys =
|
|
|
+// } else if (!devices173.isEmpty()) {
|
|
|
+// data173 = get173Data(devices173, queryTime, 3);
|
|
|
+// previousData173 = get173Data(devices173, queryTime.minusYears(1), 3);
|
|
|
+// }
|
|
|
+// break;
|
|
|
+// default:
|
|
|
+// return vo;
|
|
|
+// }
|
|
|
+//
|
|
|
+// if (!data183.isEmpty()) {
|
|
|
+// vo.setCurrent(getTotal(data183));
|
|
|
+// vo.setPrevious(getTotal(previousData183));
|
|
|
+// vo.setRatio(getRingRatio(data183, previousData183));
|
|
|
+// } else if (!data173.isEmpty()) {
|
|
|
+// vo.setCurrent(data173.get(0).getEpp());
|
|
|
+// vo.setPrevious(previousData173.get(0).getEpp());
|
|
|
+// vo.setRatio(calcMoM(queryTime, data173, previousData173));
|
|
|
+// } else {
|
|
|
+// return vo;
|
|
|
+// }
|
|
|
+//
|
|
|
+// vo.setTimeKeys(timeKeys);
|
|
|
+// vo.setAmountList(amountList);
|
|
|
+// vo.setUnit();
|
|
|
+// vo.setType(queryPeriod);
|
|
|
+// return vo;
|
|
|
+// }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取分段数据
|
|
|
+ * @param siteId 站点id
|
|
|
+ * @param queryPeriod 查询周期 day month year
|
|
|
+ * @param queryTime 查询时间
|
|
|
+ * @param queryType 查询类型(energy 能耗;electric 电;cost 费用)
|
|
|
+ * @return 分段图表数据
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public HtAnalogEnergySegmentedVo getSegmentedData(Integer siteId, String queryPeriod, LocalDateTime queryTime, String queryType) {
|
|
|
+ HtAnalogEnergySegmentedVo vo = new HtAnalogEnergySegmentedVo();
|
|
|
+ vo.setType("day".equals(queryPeriod) ? "hour" : "month".equals(queryPeriod) ? "day" : "year".equals(queryPeriod) ? "month" : "day");
|
|
|
+
|
|
|
+ /* ====== 1. 准备设备列表 ====== */
|
|
|
+ List<String> devices183 = new ArrayList<>();
|
|
|
+ List<String> devices173 = new ArrayList<>();
|
|
|
+
|
|
|
+ BigDecimal current = ZERO;
|
|
|
+ BigDecimal previous = ZERO;
|
|
|
+ BigDecimal ratio = ZERO;
|
|
|
+
|
|
|
+ List<Device> devices = getDevices(siteId);
|
|
|
+ if (devices.isEmpty()) {
|
|
|
+ log.warn("站点 {} 无设备!", siteId);
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Device device : devices) {
|
|
|
+ String deviceType = device.getDeviceType();
|
|
|
+ String deviceCode = device.getDeviceCode();
|
|
|
+ if ("1".equals(deviceType)) {
|
|
|
+ devices183.add(deviceCode);
|
|
|
+ } else if ("4".equals(deviceType)) {
|
|
|
+ devices173.add(deviceCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (devices183.isEmpty() && devices173.isEmpty()) {
|
|
|
+ log.warn("站点 {} 无有效电力设备!", siteId);
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ====== 2. 计算时间片 timeKeys ====== */
|
|
|
+ LocalDate localDate = queryTime.toLocalDate();
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
+ List<LocalDateTime> timeKeys = buildTimeKeys(queryPeriod, localDate);
|
|
|
+
|
|
|
+ /* ====== 3. 查询原始数据 ====== */
|
|
|
+ List<HtAnalogData> current183 = new ArrayList<>();
|
|
|
+ List<HtAnalogData> previous183 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> current173 = new ArrayList<>();
|
|
|
+ List<HtAnalog173Data> previous173 = new ArrayList<>();
|
|
|
+
|
|
|
+ int periodInt = periodType2Int(queryPeriod);
|
|
|
+ if (!devices183.isEmpty()) {
|
|
|
+ current183 = getAnalogData(devices183.get(0), queryTime, periodInt);
|
|
|
+ previous183 = getAnalogData(devices183.get(0), queryTime, periodInt == 1 ? 11 : periodInt == 2 ? 22 : periodInt == 3 ? 33 : 11);
|
|
|
+ } else {
|
|
|
+ current173 = get173Data(devices173, queryTime, periodInt);
|
|
|
+ previous173 = get173Data(devices173, queryTime, periodInt == 1 ? 11 : periodInt == 2 ? 22 : periodInt == 3 ? 33 : 11);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ====== 4. 计算 amountList 与总量 ====== */
|
|
|
+ List<BigDecimal> amountList = zeroList(timeKeys.size());
|
|
|
+ if (!current183.isEmpty()) {
|
|
|
+ int pastOrPresent = localDate.isBefore(today) ? 1 : 0;
|
|
|
+ amountList = buildAmountList(timeKeys, current183, periodInt, pastOrPresent);
|
|
|
+ current = (calcTotal(current183));
|
|
|
+ previous = (calcTotal(previous183));
|
|
|
+ ratio = (getRingRatio(current183, previous183));
|
|
|
+ } else if (!current173.isEmpty()) {
|
|
|
+ amountList = buildAmountList173(timeKeys, current173, periodInt);
|
|
|
+ current = (current173.get(0).getEpp());
|
|
|
+ previous = (previous173.get(0).getEpp());
|
|
|
+ ratio = (calcMoM(queryTime, current173, previous173));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询站点能耗转换情况(等价 or 当量)
|
|
|
+ SiteDynamicProperties siteDynamicProperties = siteDynamicPropertiesService.selectOne(siteId);
|
|
|
+ if (siteDynamicProperties == null) {
|
|
|
+ log.warn("站点{}未配置能耗属性等数据", siteId);
|
|
|
+ vo.setRatio(ZERO);
|
|
|
+ vo.setUnit("energy".equals(queryType) ? "吨标准煤" : "electric".equals(queryType) ? "kwh" : "cost".equals(queryType) ? "元" : "kWh");
|
|
|
+ vo.setCurrent(ZERO);
|
|
|
+ vo.setPrevious(ZERO);
|
|
|
+ vo.setTimeKeys(timeKeys);
|
|
|
+ vo.setAmountList(zeroList(timeKeys.size()));
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+ Integer demolitionStandardCoal = siteDynamicProperties.getDemolitionStandardCoal();
|
|
|
+ BigDecimal coefficient = new BigDecimal(siteDynamicProperties.getDemolitionStandardCoal1())
|
|
|
+ .divide(new BigDecimal(demolitionStandardCoal), 10, RoundingMode.DOWN);
|
|
|
+
|
|
|
+ // 根据类型设置单位 (energy 能耗;electric 电;cost)
|
|
|
+ if ("energy".equals(queryType)) {
|
|
|
+ vo.setUnit("吨标准煤");
|
|
|
+ vo.setCurrent(current.multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setPrevious(previous.multiply(coefficient).setScale(3, RoundingMode.HALF_UP));
|
|
|
+ vo.setAmountList(energyConversion(amountList, coefficient));
|
|
|
+ vo.setRatio(ratio);
|
|
|
+ } else if ("electric".equals(queryType)) {
|
|
|
+ vo.setUnit("kwh");
|
|
|
+ vo.setCurrent(current);
|
|
|
+ vo.setPrevious(previous);
|
|
|
+ vo.setAmountList(amountList);
|
|
|
+ vo.setRatio(ratio);
|
|
|
+ } else if ("cost".equals(queryType)) {
|
|
|
+ vo.setUnit("元");
|
|
|
+ switch (queryPeriod) {
|
|
|
+ case "day":
|
|
|
+ List<BigDecimal> dayCostList = cost(amountList, siteId, localDate.getMonthValue());
|
|
|
+ vo.setAmountList(dayCostList);
|
|
|
+ vo.setCurrent(dayCostList.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .reduce(ZERO, BigDecimal::add));
|
|
|
+ break;
|
|
|
+ case "month": {
|
|
|
+ List<SiteElectricityRecord> siteElectricityRecords = calculateTimeFee(siteId, localDate, 2);
|
|
|
+ vo.setCurrent(siteElectricityRecords.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .map(SiteElectricityRecord::getTotalCost)
|
|
|
+ .reduce(ZERO, BigDecimal::add));
|
|
|
+
|
|
|
+ List<SiteElectricityRecord> monthRecords = calculateTimeFee(siteId, localDate, 2);
|
|
|
+ vo.setAmountList(getMonthYearList(monthRecords, timeKeys, "month"));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case "year": {
|
|
|
+ List<SiteElectricityRecord> siteElectricityRecords = calculateTimeFee(siteId, localDate, 3);
|
|
|
+ vo.setCurrent(siteElectricityRecords.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .map(SiteElectricityRecord::getTotalCost)
|
|
|
+ .reduce(ZERO, BigDecimal::add));
|
|
|
+
|
|
|
+ List<SiteElectricityRecord> monthRecords = calculateTimeFee(siteId, localDate, 3);
|
|
|
+ vo.setAmountList(getMonthYearList(monthRecords, timeKeys, "year"));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ vo.setUnit("未知单位");
|
|
|
+ }
|
|
|
+ vo.setTimeKeys(timeKeys);
|
|
|
+ return vo;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取月、年费用列表
|
|
|
+ */
|
|
|
+ private List<BigDecimal> getMonthYearList(List<SiteElectricityRecord> records, List<LocalDateTime> timeKeys, String queryPeriod) {
|
|
|
+ List<BigDecimal> result = new ArrayList<>();
|
|
|
+ if ("month".equals(queryPeriod)) {
|
|
|
+ Map<LocalDate, SiteElectricityRecord> recordMap = records.stream()
|
|
|
+ .collect(Collectors.toMap(SiteElectricityRecord::getDate, r -> r));
|
|
|
+ result = timeKeys.stream()
|
|
|
+ .map(time -> {
|
|
|
+ SiteElectricityRecord r = recordMap.get(time.toLocalDate());
|
|
|
+ return r == null ? null : r.getTotalCost();
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ } else if ("year".equals(queryPeriod)) {
|
|
|
+ Map<YearMonth, BigDecimal> monthMap = records.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ r -> YearMonth.from(r.getDate()),
|
|
|
+ Collectors.reducing(ZERO,
|
|
|
+ SiteElectricityRecord::getTotalCost,
|
|
|
+ BigDecimal::add)));
|
|
|
+
|
|
|
+ result = timeKeys.stream()
|
|
|
+ .map(t -> monthMap.getOrDefault(YearMonth.from(t), null))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 日费用计算
|
|
|
+ */
|
|
|
+ private List<BigDecimal> cost(List<BigDecimal> dataList, Integer siteId, Integer month) {
|
|
|
+ // 1. 预填充 24 个 null,避免 set 越界
|
|
|
+ List<BigDecimal> costList = new ArrayList<>(Collections.nCopies(24, null));
|
|
|
+
|
|
|
+ List<ElectricityTimePrice> priceList = getElectricityTimePrice(siteId);
|
|
|
+
|
|
|
+ // 2. 不分时
|
|
|
+ for (ElectricityTimePrice p : priceList) {
|
|
|
+ if (!month.equals(p.getMonth())) continue;
|
|
|
+ if (p.getPriceType().equals(2)) {
|
|
|
+ BigDecimal price = p.getElectricityPrice();
|
|
|
+ for (int h = 0; h < 24; h++) {
|
|
|
+ BigDecimal val = dataList.get(h);
|
|
|
+ costList.set(h, val == null ? null : val.multiply(price).setScale(2, RoundingMode.HALF_UP));
|
|
|
+ }
|
|
|
+ return costList;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 分时
|
|
|
+ for (ElectricityTimePrice p : priceList) {
|
|
|
+ if (!month.equals(p.getMonth()) || !p.getPriceType().equals(1)) continue;
|
|
|
+
|
|
|
+ int start = p.getStartTime().getHour();
|
|
|
+ int end = p.getEndTime().getHour(); // 约定 start < end
|
|
|
+ BigDecimal price = p.getElectricityPrice();
|
|
|
+
|
|
|
+ for (int h = start; h < end; h++) {
|
|
|
+ BigDecimal val = dataList.get(h);
|
|
|
+ costList.set(h, val == null ? null : val.multiply(price).setScale(2, RoundingMode.HALF_UP));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return costList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取站点的时段计价
|
|
|
+ */
|
|
|
+ private List<ElectricityTimePrice> getElectricityTimePrice(Integer siteId) {
|
|
|
+ LambdaQueryWrapper<ElectricityTimePrice> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.select(ElectricityTimePrice::getMonth, ElectricityTimePrice::getStartTime, ElectricityTimePrice::getEndTime, ElectricityTimePrice::getElectricityPrice, ElectricityTimePrice::getPriceType)
|
|
|
+ .eq(ElectricityTimePrice::getSiteId, siteId);
|
|
|
+ return electricityTimePriceMapper.selectList(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 能耗转换
|
|
|
+ */
|
|
|
+ private List<BigDecimal> energyConversion(List<BigDecimal> amountList, BigDecimal coefficient) {
|
|
|
+ return amountList.stream()
|
|
|
+ .map(e -> Optional.ofNullable(e)
|
|
|
+ .map(v -> v.multiply(coefficient).setScale(3, RoundingMode.HALF_UP))
|
|
|
+ .orElse(null))
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 根据 queryPeriod 生成“从周期第一天 00:00 开始”的列表 */
|
|
|
+ private List<LocalDateTime> buildTimeKeys(String queryPeriod, LocalDate base) {
|
|
|
+ List<LocalDateTime> list = new ArrayList<>();
|
|
|
+ switch (queryPeriod) {
|
|
|
+ case "day":
|
|
|
+ // 00:00 ~ 23:00 共 24 个时间点
|
|
|
+ for (int i = 0; i < 24; i++) {
|
|
|
+ list.add(base.atStartOfDay().plusHours(i));
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case "month":
|
|
|
+ // 当月每一天的 00:00
|
|
|
+ YearMonth ym = YearMonth.from(base);
|
|
|
+ LocalDate start = ym.atDay(1);
|
|
|
+ int days = ym.lengthOfMonth();
|
|
|
+ for (int i = 0; i < days; i++) {
|
|
|
+ list.add(start.plusDays(i).atStartOfDay());
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case "year":
|
|
|
+ // 当年 1~12 月,每月 1 号 00:00
|
|
|
+ LocalDate yearStart = base.withDayOfYear(1);
|
|
|
+ for (int i = 0; i < 12; i++) {
|
|
|
+ list.add(yearStart.plusMonths(i).atStartOfDay());
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ throw new BusinessException("queryPeriod 参数错误!检查后重试");
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算每个小时的【消耗电量】
|
|
|
+ * 规则:如果一小时内有多个数据,则用(lastEpp - firstEpp)
|
|
|
+ * 如果一小时内只有一个数据,则用(currentEpp - previousHourLastEpp)
|
|
|
+ * 如果没有数据,则使用0
|
|
|
+ */
|
|
|
+ /*private List<BigDecimal> buildAmountList(List<LocalDateTime> timeKeys,
|
|
|
+ List<HtAnalogData> src) {
|
|
|
+ if (src.isEmpty()) {
|
|
|
+ return zeroList(timeKeys.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 先把原始数据按“小时起点”分组
|
|
|
+ Map<LocalDateTime, List<HtAnalogData>> groupByHour =
|
|
|
+ src.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ d -> alignToPeriod(d.getDataTime(), "hour")));
|
|
|
+
|
|
|
+ List<BigDecimal> result = new ArrayList<>(timeKeys.size());
|
|
|
+ BigDecimal previousLast = null; // 上一小时的最后一个值
|
|
|
+
|
|
|
+ for (LocalDateTime hourStart : timeKeys) {
|
|
|
+ List<HtAnalogData> oneHour = groupByHour.get(hourStart);
|
|
|
+ if (oneHour == null || oneHour.isEmpty()) {
|
|
|
+ result.add(ZERO);
|
|
|
+ } else {
|
|
|
+ // 升序排序
|
|
|
+ oneHour.sort(Comparator.comparing(HtAnalogData::getDataTime));
|
|
|
+ BigDecimal first = oneHour.get(0).getEpp();
|
|
|
+ BigDecimal last = oneHour.get(oneHour.size() - 1).getEpp();
|
|
|
+
|
|
|
+ BigDecimal amount;
|
|
|
+ if (oneHour.size() == 1 && previousLast != null) {
|
|
|
+ // 只有一条数据且有上一小时的数据,用上一小时最后值计算
|
|
|
+ amount = last.subtract(previousLast);
|
|
|
+ } else {
|
|
|
+ // 多条数据,用本小时内差值
|
|
|
+ amount = last.subtract(first);
|
|
|
+ }
|
|
|
+
|
|
|
+ result.add(amount);
|
|
|
+ previousLast = last; // 更新上一小时的最后值
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }*/
|
|
|
+ private List<BigDecimal> buildAmountList(List<LocalDateTime> timeKeys,
|
|
|
+ List<HtAnalogData> src,
|
|
|
+ int periodInt,
|
|
|
+ int periodPastOrPresent) {
|
|
|
+
|
|
|
+ String period = periodInt == 1 ? "hour"
|
|
|
+ : periodInt == 2 ? "day"
|
|
|
+ : periodInt == 3 ? "month"
|
|
|
+ : "hour";
|
|
|
+
|
|
|
+ if (src.isEmpty()) {
|
|
|
+ return zeroOrNullList(timeKeys.size(), periodPastOrPresent, period, timeKeys);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 原始数据按周期起点分组
|
|
|
+ Map<LocalDateTime, List<HtAnalogData>> groupByPeriod =
|
|
|
+ src.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ d -> alignToPeriod(d.getDataTime(), period)));
|
|
|
+
|
|
|
+ // 当前周期起点
|
|
|
+ LocalDateTime nowPeriodStart = alignToPeriod(LocalDateTime.now(), period);
|
|
|
+
|
|
|
+ List<BigDecimal> result = new ArrayList<>(timeKeys.size());
|
|
|
+
|
|
|
+ for (LocalDateTime periodStart : timeKeys) {
|
|
|
+ // 如果要求对未来补 null 且当前 periodStart 晚于 nowPeriodStart
|
|
|
+ if (periodPastOrPresent == 0 && periodStart.isAfter(nowPeriodStart)) {
|
|
|
+ result.add(null);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<HtAnalogData> oneGroup = groupByPeriod.get(periodStart);
|
|
|
+ if (oneGroup == null || oneGroup.isEmpty()) {
|
|
|
+ result.add(ZERO);
|
|
|
+ } else {
|
|
|
+ oneGroup.sort(Comparator.comparing(HtAnalogData::getDataTime));
|
|
|
+ BigDecimal first = oneGroup.get(0).getEpp();
|
|
|
+ BigDecimal last = oneGroup.get(oneGroup.size() - 1).getEpp();
|
|
|
+ result.add(last.subtract(first));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 当 src 为空时,根据 periodPastOrPresent 决定补 0 还是补 null。
|
|
|
+ * periodPastOrPresent == 0 时,把未来时间补 null,其余补 0。
|
|
|
+ */
|
|
|
+ private List<BigDecimal> zeroOrNullList(int size,
|
|
|
+ int periodPastOrPresent,
|
|
|
+ String period,
|
|
|
+ List<LocalDateTime> timeKeys) {
|
|
|
+ if (periodPastOrPresent == 1) {
|
|
|
+ // 全部补 0
|
|
|
+ return Collections.nCopies(size, ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ LocalDateTime nowPeriodStart = alignToPeriod(LocalDateTime.now(), period);
|
|
|
+ List<BigDecimal> list = new ArrayList<>(size);
|
|
|
+ for (LocalDateTime periodStart : timeKeys) {
|
|
|
+ if (periodStart.isAfter(nowPeriodStart)) {
|
|
|
+ list.add(null);
|
|
|
+ } else {
|
|
|
+ list.add(ZERO);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**173 设备同理 */
|
|
|
+ /*private List<BigDecimal> buildAmountList173(List<LocalDateTime> timeKeys,
|
|
|
+ List<HtAnalog173Data> src) {
|
|
|
+ if (src.isEmpty()) {
|
|
|
+ return zeroList(timeKeys.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<LocalDateTime, List<HtAnalog173Data>> groupByHour =
|
|
|
+ src.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ d -> alignToPeriod(d.getDataTime(), "hour")));
|
|
|
+
|
|
|
+ List<BigDecimal> result = new ArrayList<>(timeKeys.size());
|
|
|
+ BigDecimal previousLast = null; // 上一小时的最后一个值
|
|
|
+
|
|
|
+ for (LocalDateTime hourStart : timeKeys) {
|
|
|
+ List<HtAnalog173Data> oneHour = groupByHour.get(hourStart);
|
|
|
+ if (oneHour == null || oneHour.isEmpty()) {
|
|
|
+ result.add(ZERO);
|
|
|
+ } else {
|
|
|
+ oneHour.sort(Comparator.comparing(HtAnalog173Data::getDataTime));
|
|
|
+ BigDecimal first = oneHour.get(0).getEpp();
|
|
|
+ BigDecimal last = oneHour.get(oneHour.size() - 1).getEpp();
|
|
|
+
|
|
|
+ BigDecimal amount;
|
|
|
+ if (oneHour.size() == 1 && previousLast != null) {
|
|
|
+ // 只有一条数据且有上一小时的数据,用上一小时最后值计算
|
|
|
+ amount = last.subtract(previousLast);
|
|
|
+ } else {
|
|
|
+ // 多条数据,用本小时内差值
|
|
|
+ amount = last.subtract(first);
|
|
|
+ }
|
|
|
+
|
|
|
+ result.add(amount);
|
|
|
+ // 更新上一小时的最后值
|
|
|
+ previousLast = last;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }*/
|
|
|
+ private List<BigDecimal> buildAmountList173(List<LocalDateTime> timeKeys,
|
|
|
+ List<HtAnalog173Data> src,
|
|
|
+ int periodInt) {
|
|
|
+ String period = periodInt == 1 ? "hour" : periodInt == 2 ? "day" : periodInt == 3 ? "month" : "hour";
|
|
|
+ if (src.isEmpty()) {
|
|
|
+ return zeroList(timeKeys.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<LocalDateTime, List<HtAnalog173Data>> groupByHour =
|
|
|
+ src.stream()
|
|
|
+ .collect(Collectors.groupingBy(
|
|
|
+ d -> alignToPeriod(d.getDataTime(), period)));
|
|
|
+
|
|
|
+ List<BigDecimal> result = new ArrayList<>(timeKeys.size());
|
|
|
+
|
|
|
+ for (LocalDateTime hourStart : timeKeys) {
|
|
|
+ List<HtAnalog173Data> oneHour = groupByHour.get(hourStart);
|
|
|
+ if (oneHour == null || oneHour.isEmpty()) {
|
|
|
+ result.add(ZERO);
|
|
|
+ } else {
|
|
|
+ oneHour.sort(Comparator.comparing(HtAnalog173Data::getDataTime));
|
|
|
+ BigDecimal first = oneHour.get(0).getEpp();
|
|
|
+ BigDecimal last = oneHour.get(oneHour.size() - 1).getEpp();
|
|
|
+ result.add(last.subtract(first));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 把一个时间对齐到时间片起点(小时/天/月) */
|
|
|
+ private LocalDateTime alignToPeriod(LocalDateTime t, String period) {
|
|
|
+ switch (period) {
|
|
|
+ case "hour":
|
|
|
+ return t.withMinute(0).withSecond(0).withNano(0);
|
|
|
+ case "day":
|
|
|
+ return t.toLocalDate().atStartOfDay();
|
|
|
+ case "month":
|
|
|
+ return t.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0).withNano(0);
|
|
|
+ default:
|
|
|
+ throw new IllegalArgumentException();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 用“最后一条 - 第一条”计算周期总量 */
|
|
|
+ private BigDecimal calcTotal(List<HtAnalogData> list) {
|
|
|
+ if (list.size() < 2) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+ return list.get(0).getEpp()
|
|
|
+ .subtract(list.get(list.size() - 1).getEpp());
|
|
|
+ }
|
|
|
+
|
|
|
+ private int periodType2Int(String period) {
|
|
|
+ switch (period) {
|
|
|
+ case "day":
|
|
|
+ return 1;
|
|
|
+ case "month":
|
|
|
+ return 2;
|
|
|
+ case "year":
|
|
|
+ return 3;
|
|
|
+ default:
|
|
|
+ throw new BusinessException("period 参数错误!检查后重试");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 返回一个固定长度的 0 列表,避免空数组 */
|
|
|
+ private List<BigDecimal> zeroList(int size) {
|
|
|
+ return new ArrayList<>(Collections.nCopies(size, ZERO));
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 获取一个站点的费率配置-基本电价配置 */
|
|
|
+ public ElectricityRateConfig getElectricityRateConfig(Integer siteId) {
|
|
|
+ LambdaQueryWrapper<ElectricityRateConfig> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.select(ElectricityRateConfig::getExcessPercentage, ElectricityRateConfig::getAdditionalMultiplier,
|
|
|
+ ElectricityRateConfig::getDemandPrice, ElectricityRateConfig::getDeclaredDemand, ElectricityRateConfig::getBillingMethod,
|
|
|
+ ElectricityRateConfig::getRatedCapacity, ElectricityRateConfig::getCapacityPrice)
|
|
|
+ .eq(ElectricityRateConfig::getSiteId, siteId);
|
|
|
+ ElectricityRateConfig config = electricityRateConfigMapper.selectOne(wrapper);
|
|
|
+ if (config == null) {
|
|
|
+ throw new BusinessException("未找到该站点的电费配置!");
|
|
|
+ }
|
|
|
+ return config;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取基础电费
|
|
|
+ * @param list 历史数据
|
|
|
+ * @param config 费率配置
|
|
|
+ * @param siteId 站点ID
|
|
|
+ * @param electricity 电量
|
|
|
+ * @return 基础电费
|
|
|
+ */
|
|
|
+ public BigDecimal getBasicExpenses(List<HtAnalogData> list, ElectricityRateConfig config, Integer siteId, BigDecimal electricity) {
|
|
|
+
|
|
|
+ BigDecimal basicExpenses = ZERO;
|
|
|
+ // 超过的百分比
|
|
|
+ BigDecimal excessPercentage = config.getExcessPercentage();
|
|
|
+ // 超过部分的计费倍数
|
|
|
+ BigDecimal multiple = config.getAdditionalMultiplier();
|
|
|
+ // 额定容量(kVA)
|
|
|
+ BigDecimal ratedCapacity = config.getRatedCapacity();
|
|
|
+ // 容量电价(元/ 千伏安)
|
|
|
+ BigDecimal capacityPrice = config.getCapacityPrice();
|
|
|
+ // 需量电价(元/ 千瓦)
|
|
|
+ BigDecimal demandPrice = config.getDemandPrice();
|
|
|
+ // 申报需量(kW)
|
|
|
+ BigDecimal declaredDemand = config.getDeclaredDemand();
|
|
|
+ // 基本电费核算方式(1 按合同最大需量, 2 按实际最大需量, 3 按变压器容量;默认 2)
|
|
|
+ Integer billingMethod = config.getBillingMethod();
|
|
|
+
|
|
|
+ switch (billingMethod) {
|
|
|
+ case 1:
|
|
|
+ // 按合同最大需量
|
|
|
+ basicExpenses = calculateContractDemandFee(list, declaredDemand, demandPrice, excessPercentage, multiple);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ // 按实际最大需量
|
|
|
+ basicExpenses = calculateActualDemandFee(list, demandPrice);
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ // 按变压器容量
|
|
|
+ basicExpenses = calculateTransformerCapacityFee(ratedCapacity, capacityPrice);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ BigDecimal additionalElectricityPrice = additionalElectricityPrice(siteId, electricity);
|
|
|
+ if (additionalElectricityPrice.compareTo(ZERO) > 0) {
|
|
|
+ basicExpenses = basicExpenses.add(additionalElectricityPrice);
|
|
|
+ }
|
|
|
+
|
|
|
+ return basicExpenses;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取附加电费
|
|
|
+ * @param siteId 站点ID
|
|
|
+ * @return 附加电费
|
|
|
+ */
|
|
|
+ private BigDecimal additionalElectricityPrice(Integer siteId, BigDecimal electricity) {
|
|
|
+ return getSiteInformation(siteId).stream()
|
|
|
+ .map(SiteInformation::getAdditionalElectricityPrice)
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .reduce(ZERO, BigDecimal::add)
|
|
|
+ .multiply(electricity)
|
|
|
+ .setScale(2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取站点附加电费信息
|
|
|
+ * @param siteId 站点ID
|
|
|
+ * @return 站点附加电费信息
|
|
|
+ */
|
|
|
+ // private List<SiteInformation> getSiteInformation(Integer siteId) {
|
|
|
+ // // 构建查询条件,只查询需要的字段
|
|
|
+ // LambdaQueryWrapper<SiteInformation> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ // queryWrapper.eq(SiteInformation::getSiteId, siteId);
|
|
|
+ //
|
|
|
+ // // 查询站点信息
|
|
|
+ // List<SiteInformation> siteInformations = siteInformationMapper.selectList(queryWrapper);
|
|
|
+ //
|
|
|
+ // // 处理空集合(无记录时直接返回空)
|
|
|
+ // if (CollectionUtils.isEmpty(siteInformations)) {
|
|
|
+ // return Collections.emptyList();
|
|
|
+ // }
|
|
|
+ //
|
|
|
+ // // 筛选出附加电费不为null的记录
|
|
|
+ // List<SiteInformation> nonNullPriceList = siteInformations.stream()
|
|
|
+ // .filter(info -> info.getAdditionalElectricityPrice() != null)
|
|
|
+ // .collect(Collectors.toList());
|
|
|
+ //
|
|
|
+ // // 判断:若所有记录的附加电费都为null(即筛选后集合为空),则返回空集合;否则返回筛选结果
|
|
|
+ // return nonNullPriceList.isEmpty() ? Collections.emptyList() : nonNullPriceList;
|
|
|
+ // }
|
|
|
+ private List<SiteInformation> getSiteInformation(Integer siteId) {
|
|
|
+ return siteInformationMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<SiteInformation>()
|
|
|
+ .eq(SiteInformation::getSiteId, siteId))
|
|
|
+ .stream()
|
|
|
+ .filter(info -> info.getAdditionalElectricityPrice() != null)
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算实际最大需求
|
|
|
+ * @param dataList 数据列表
|
|
|
+ * @return 实际最大需量电费
|
|
|
+ */
|
|
|
+ private BigDecimal calculateActualMaxDemand(List<HtAnalogData> dataList) {
|
|
|
+ BigDecimal maxDemand = ZERO;
|
|
|
+
|
|
|
+ for (int i = 0; i < dataList.size() - 1; i++) {
|
|
|
+ HtAnalogData start = dataList.get(i);
|
|
|
+ HtAnalogData end = dataList.get(i + 1);
|
|
|
+
|
|
|
+ // 计算时间差(分钟)
|
|
|
+ long minutes = ChronoUnit.MINUTES.between(start.getDataTime(), end.getDataTime());
|
|
|
+
|
|
|
+ // 动态窗口:仅计算10~20分钟内的数据(避免跨度过大或过小)
|
|
|
+ if (minutes >= 10 && minutes <= 20) {
|
|
|
+ BigDecimal deltaEpp = end.getEpp().subtract(start.getEpp());
|
|
|
+ BigDecimal avgPower = deltaEpp.divide(new BigDecimal(minutes / 60.0), 3, RoundingMode.HALF_UP);
|
|
|
+ maxDemand = maxDemand.max(avgPower);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return maxDemand;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算合同最大需量电费(含超额惩罚)
|
|
|
+ * @param dataList 数据列表
|
|
|
+ * @param contractDemand 合同最大需量/申报需量(kW)
|
|
|
+ * @param demandPrice 需量电价
|
|
|
+ * @return 合同最大需量电费
|
|
|
+ */
|
|
|
+ private BigDecimal calculateContractDemandFee(List<HtAnalogData> dataList, BigDecimal contractDemand, BigDecimal demandPrice,
|
|
|
+ BigDecimal excessPercentage, BigDecimal multiple) {
|
|
|
+ BigDecimal actualDemand = calculateActualMaxDemand(dataList);
|
|
|
+
|
|
|
+ // 允许n%浮动
|
|
|
+ BigDecimal overDemand = actualDemand.subtract(contractDemand.multiply(new BigDecimal(1).add(excessPercentage)));
|
|
|
+
|
|
|
+ if (overDemand.compareTo(ZERO) <= 0) {
|
|
|
+ // 未超105%,按合同计费
|
|
|
+ return contractDemand.multiply(demandPrice);
|
|
|
+ } else {
|
|
|
+ // 超出部分按n倍计费
|
|
|
+ return contractDemand.multiply(demandPrice).add(overDemand.multiply(multiple).multiply(demandPrice));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算实际最大需量电费(无惩罚)
|
|
|
+ * @param dataList 数据列表
|
|
|
+ * @param demandPrice 需量电价
|
|
|
+ * @return 实际最大需量电费
|
|
|
+ */
|
|
|
+ private BigDecimal calculateActualDemandFee(List<HtAnalogData> dataList, BigDecimal demandPrice) {
|
|
|
+ BigDecimal actualDemand = calculateActualMaxDemand(dataList);
|
|
|
+ return actualDemand.multiply(demandPrice);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算变压器容量电费(固定值)
|
|
|
+ * @param transformerCapacity 变压器容量
|
|
|
+ * @param capacityPrice 变压器容量电价
|
|
|
+ * @return 变压器容量电费
|
|
|
+ * */
|
|
|
+ private BigDecimal calculateTransformerCapacityFee(BigDecimal transformerCapacity, BigDecimal capacityPrice) {
|
|
|
+ return transformerCapacity.multiply(capacityPrice);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分时电费查询
|
|
|
+ * @param siteId 站点ID
|
|
|
+ * @param queryDate 查询日期
|
|
|
+ * @param queryType 查询类型
|
|
|
+ * */
|
|
|
+ private List<SiteElectricityRecord> calculateTimeFee(Integer siteId, LocalDate queryDate, Integer queryType) {
|
|
|
+ LocalDate monthFirstDay = queryDate.with(TemporalAdjusters.firstDayOfMonth());
|
|
|
+ LocalDate monthLastDay = queryDate.with(TemporalAdjusters.lastDayOfMonth());
|
|
|
+ LocalDate yearFirstDay = queryDate.with(TemporalAdjusters.firstDayOfYear());
|
|
|
+ LocalDate yearLastDay = queryDate.with(TemporalAdjusters.lastDayOfYear());
|
|
|
+
|
|
|
+ LambdaQueryWrapper<SiteElectricityRecord> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.select(SiteElectricityRecord::getTotalCost, SiteElectricityRecord::getDate)
|
|
|
+ .eq(SiteElectricityRecord::getSiteId, siteId);
|
|
|
+
|
|
|
+ switch (queryType) {
|
|
|
+ case 1:
|
|
|
+ queryWrapper.eq(SiteElectricityRecord::getDate, queryDate);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ queryWrapper.between(SiteElectricityRecord::getDate, monthFirstDay, monthLastDay);
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ queryWrapper.between(SiteElectricityRecord::getDate, yearFirstDay, yearLastDay);
|
|
|
+ break;
|
|
|
+ case 22:
|
|
|
+ queryWrapper.between(SiteElectricityRecord::getDate, monthFirstDay, queryDate);
|
|
|
+ break;
|
|
|
+ case 33:
|
|
|
+ queryWrapper.between(SiteElectricityRecord::getDate, yearFirstDay, queryDate);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return siteElectricityRecordMapper.selectList(queryWrapper);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算总费用
|
|
|
+ *
|
|
|
+ * @param records 电费记录列表
|
|
|
+ * @return 总费用
|
|
|
+ */
|
|
|
+ private BigDecimal calculateTotalCost(List<SiteElectricityRecord> records) {
|
|
|
+ if (records == null || records.isEmpty()) {
|
|
|
+ return ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ return records.stream()
|
|
|
+ .map(SiteElectricityRecord::getTotalCost)
|
|
|
+ .reduce(ZERO, BigDecimal::add);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
}
|