diff --git a/ems-common/src/main/java/com/xzzn/common/enums/CostType.java b/ems-common/src/main/java/com/xzzn/common/enums/CostType.java new file mode 100644 index 0000000..19632bb --- /dev/null +++ b/ems-common/src/main/java/com/xzzn/common/enums/CostType.java @@ -0,0 +1,42 @@ +package com.xzzn.common.enums; + +/** + * 电量类型 + */ +public enum CostType +{ + PEAK("peak", "尖"), + HIGH("high", "峰"), + FLAT("flat", "平"), + VALLEY("valley", "谷"), + ; + + private final String code; + private final String info; + + CostType(String code, String info) + { + this.code = code; + this.info = info; + } + + public String getCode() + { + return code; + } + + public String getInfo() + { + return info; + } + + public static CostType getEnumByCode(String code) + { + for (CostType costType : CostType.values()) { + if (costType.code.equals(code)) { + return costType; + } + } + return null; + } +} diff --git a/ems-common/src/main/java/com/xzzn/common/utils/DateUtils.java b/ems-common/src/main/java/com/xzzn/common/utils/DateUtils.java index fb0ddc2..29ff17c 100644 --- a/ems-common/src/main/java/com/xzzn/common/utils/DateUtils.java +++ b/ems-common/src/main/java/com/xzzn/common/utils/DateUtils.java @@ -1,5 +1,7 @@ package com.xzzn.common.utils; +import com.xzzn.common.annotation.Log; + import java.lang.management.ManagementFactory; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -9,11 +11,13 @@ import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import org.apache.commons.lang3.time.DateFormatUtils; +import org.apache.commons.logging.LogFactory; /** * 时间工具类 @@ -22,6 +26,8 @@ import org.apache.commons.lang3.time.DateFormatUtils; */ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { + private static final org.apache.commons.logging.Log log = LogFactory.getLog(DateUtils.class); + public static String YYYY = "yyyy"; public static String YYYY_MM = "yyyy-MM"; @@ -408,4 +414,49 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils // 格式化并返回 return yesterday.format(formatter); } + + /** + * 获取日期的开始时间 + * @param dateString 格式为yyyy-MM-dd的日期字符串 + * @return 日期的开始时间字符串 + */ + public static String getDayBeginString(String dateString) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + try { + // 解析日期字符串 + LocalDate date = LocalDate.parse(dateString, formatter); + + // 创建时间段的开始时间 00:00:00 + LocalDateTime startTime = date.atTime(LocalTime.MIN); + + return convertToString(startTime); + } catch (DateTimeParseException e) { + log.info("Error parsing date: " + e.getMessage()); + } + + return dateString + " 00:00:00"; + } + + /** + * 获取日期的结束时间 + * @param dateString 格式为yyyy-MM-dd的日期字符串 + * @return 日期的结束时间字符串 + */ + public static String getDayEndString(String dateString) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + try { + // 解析日期字符串 + LocalDate date = LocalDate.parse(dateString, formatter); + + // 创建时间段的结束时间 23:59:59 + LocalDateTime endTime = date.atTime(LocalTime.MAX); + + return convertToString(endTime); + } catch (DateTimeParseException e) { + log.info("Error parsing date: " + e.getMessage()); + } + + return dateString + " 23:59:59"; + } + } diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterStatisListVo.java b/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterStatisListVo.java index 91b69bf..405e144 100644 --- a/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterStatisListVo.java +++ b/ems-system/src/main/java/com/xzzn/ems/domain/vo/AmmeterStatisListVo.java @@ -11,6 +11,8 @@ public class AmmeterStatisListVo { /** 类别 */ private String dataTime; + private String timePart; + /** 组合有功-总 (kWh) */ private BigDecimal activeTotalKwh = BigDecimal.ZERO; @@ -52,6 +54,14 @@ public class AmmeterStatisListVo { this.dataTime = dataTime; } + public String getTimePart() { + return timePart; + } + + public void setTimePart(String timePart) { + this.timePart = timePart; + } + public BigDecimal getActiveTotalKwh() { return activeTotalKwh; } diff --git a/ems-system/src/main/java/com/xzzn/ems/domain/vo/EnergyPriceConfigVo.java b/ems-system/src/main/java/com/xzzn/ems/domain/vo/EnergyPriceConfigVo.java new file mode 100644 index 0000000..ef7635d --- /dev/null +++ b/ems-system/src/main/java/com/xzzn/ems/domain/vo/EnergyPriceConfigVo.java @@ -0,0 +1,101 @@ +package com.xzzn.ems.domain.vo; + +import com.xzzn.common.annotation.Excel; + +import java.math.BigDecimal; +import java.util.List; + +/** + * 电价配置-电价列表-对象 + * + */ +public class EnergyPriceConfigVo { + + /** 时间格式 yyyy-MM */ + private String yearMonth; + /** 尖电价(元/kWh) */ + @Excel(name = "尖电价(元/kWh)") + private BigDecimal peak; + /** 峰电价(元/kWh) */ + @Excel(name = "峰电价(元/kWh)") + private BigDecimal high; + /** 平电价(元/kWh) */ + @Excel(name = "平电价(元/kWh)") + private BigDecimal flat; + /** 谷电价(元/kWh) */ + @Excel(name = "谷电价(元/kWh)") + private BigDecimal valley; + /** 时段开始时间 */ + @Excel(name = "时段开始时间") + private String startTime; + /** 时段结束时间 */ + @Excel(name = "时段结束时间") + private String endTime; + /** 电价类型: 尖-peak,峰-high,平-flat,谷=valley */ + @Excel(name = "电价类型: 尖-peak,峰-high,平-flat,谷=valley") + private String costType; + + public String getYearMonth() { + return yearMonth; + } + + public void setYearMonth(String yearMonth) { + this.yearMonth = yearMonth; + } + + public BigDecimal getPeak() { + return peak; + } + + public void setPeak(BigDecimal peak) { + this.peak = peak; + } + + public BigDecimal getHigh() { + return high; + } + + public void setHigh(BigDecimal high) { + this.high = high; + } + + public BigDecimal getFlat() { + return flat; + } + + public void setFlat(BigDecimal flat) { + this.flat = flat; + } + + public BigDecimal getValley() { + return valley; + } + + public void setValley(BigDecimal valley) { + this.valley = valley; + } + + public String getStartTime() { + return startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + + public String getCostType() { + return costType; + } + + public void setCostType(String costType) { + this.costType = costType; + } +} diff --git a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsAmmeterDataMapper.java b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsAmmeterDataMapper.java index 62a1bdf..3593730 100644 --- a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsAmmeterDataMapper.java +++ b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsAmmeterDataMapper.java @@ -93,4 +93,10 @@ public interface EmsAmmeterDataMapper // 获取最新数据 public EmsAmmeterData getLastData(@Param("siteId")String siteId, @Param("deviceId")String deviceId); + List selectHourlyAmmeterData(@Param("siteId") String siteId, + @Param("startTime") String startTime, + @Param("endTime") String endTime); + List selectDailyAmmeterData(@Param("siteId") String siteId, + @Param("startTime") String startTime, + @Param("endTime") String endTime); } diff --git a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsEnergyPriceConfigMapper.java b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsEnergyPriceConfigMapper.java index 2dfbe86..95041c4 100644 --- a/ems-system/src/main/java/com/xzzn/ems/mapper/EmsEnergyPriceConfigMapper.java +++ b/ems-system/src/main/java/com/xzzn/ems/mapper/EmsEnergyPriceConfigMapper.java @@ -3,6 +3,7 @@ package com.xzzn.ems.mapper; import java.util.List; import com.xzzn.ems.domain.EmsEnergyPriceConfig; +import com.xzzn.ems.domain.vo.EnergyPriceConfigVo; import com.xzzn.ems.domain.vo.EnergyPriceTimeRange; import org.apache.ibatis.annotations.Param; @@ -77,7 +78,7 @@ public interface EmsEnergyPriceConfigMapper public List getAllSitePriceConfig( @Param("currentYear")int currentYear, @Param("currentMonth")int currentMonth); // 查询指定时间范围的电价配置列表 - public List getConfigListByTimeFrame(@Param("siteId")String siteId, - @Param("startTime")String startTime, - @Param("endTime")String endTime); + public List getConfigListByTimeFrame(@Param("siteId")String siteId, + @Param("startDate")String startDate, + @Param("endDate")String endDate); } diff --git a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java index 9c4641b..cf6b466 100644 --- a/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java +++ b/ems-system/src/main/java/com/xzzn/ems/service/impl/EmsStatsReportServiceImpl.java @@ -1,5 +1,6 @@ package com.xzzn.ems.service.impl; +import com.xzzn.common.enums.CostType; import com.xzzn.common.enums.SiteEnum; import com.xzzn.common.utils.DateUtils; import com.xzzn.ems.domain.EmsAmmeterData; @@ -16,6 +17,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.function.Function; @@ -312,38 +316,122 @@ public class EmsStatsReportServiceImpl implements IEmsStatsReportService @Override public List getAmmeterRevenueDataResult(StatisAmmeterDateRequest requestVo) { - //查询电表数据 - List dataList = emsDailyEnergyDataMapper.getDataBySiteId(requestVo.getSiteId(), requestVo.getStartTime(), requestVo.getEndTime()); - if (CollectionUtils.isEmpty(dataList)){ - return null; - } - //查询电价配置 - List priceConfigList = emsEnergyPriceConfigMapper.getConfigListByTimeFrame(requestVo.getSiteId(), requestVo.getStartTime(), requestVo.getEndTime()); - if (CollectionUtils.isEmpty(priceConfigList)){ - return null; - } - Map priceConfigMap = priceConfigList.stream().collect(Collectors.toMap(data -> data.getYear() + "-" + String.format("%02d", Integer.parseInt(data.getMonth())), Function.identity())); + String siteId = requestVo.getSiteId(); + String startTime = DateUtils.getDayBeginString(requestVo.getStartTime()); + String endTime = DateUtils.getDayEndString(requestVo.getEndTime()); List resultList = new ArrayList<>(); - dataList.forEach(ammeter -> { - EmsEnergyPriceConfig price = priceConfigMap.get(ammeter.getDataTime().substring(0, 7)); - resultList.add(calculateDailyBill(ammeter, price)); + List dataList = new ArrayList<>(); + //查询电价配置 + List priceConfigList = emsEnergyPriceConfigMapper.getConfigListByTimeFrame(siteId, requestVo.getStartTime(), requestVo.getEndTime()); + if (CollectionUtils.isEmpty(priceConfigList)){ + return Collections.emptyList(); + } + //查询电表数据 + if (SiteEnum.FX.getCode().equals(siteId)) { + dataList = emsAmmeterDataMapper.selectHourlyAmmeterData(siteId, startTime, endTime); + } else { + // 其他站点暂时默认与电动所内部一致处理,按天查询数据 + dataList = emsAmmeterDataMapper.selectDailyAmmeterData(siteId, startTime, endTime); + } + if (CollectionUtils.isEmpty(dataList)) { + return Collections.emptyList(); + } + Map> priceConfigMap = priceConfigList.stream().collect(Collectors.groupingBy(EnergyPriceConfigVo::getYearMonth)); + Map> ammeterMap = dataList.stream().collect(Collectors.groupingBy(AmmeterStatisListVo::getDataTime)); + List dateList = generateTargetDates(requestVo.getStartTime(), requestVo.getEndTime()); + dateList.forEach(date -> { + String dateTime = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + List priceConfigs = priceConfigMap.get(dateTime.substring(0, 7)); + List ammeterStatisListVos = ammeterMap.get(dateTime); + resultList.add(calculateDailyBill(siteId, dateTime, ammeterStatisListVos, priceConfigs)); }); return resultList; } - public static AmmeterRevenueStatisListVo calculateDailyBill(AmmeterStatisListVo ammeter, EmsEnergyPriceConfig price) { + public static AmmeterRevenueStatisListVo calculateDailyBill(String siteId, String dateTime, List ammeterList, List priceList) { AmmeterRevenueStatisListVo ammeterRevenue = new AmmeterRevenueStatisListVo(); - ammeterRevenue.setDataTime(ammeter.getDataTime()); - if (price != null) { -// BigDecimal activeTotalPrice = ammeter.getActiveTotalKwh().multiply(new BigDecimal(price.getPeak())); -// BigDecimal activePeakPrice = ammeter.getActivePeakKwh().multiply(new BigDecimal(price.getPeak())); -// BigDecimal activeHighPrice = ammeter.getActiveHighKwh().multiply(new BigDecimal(price.getHigh())); -// BigDecimal activeFlatPrice = ammeter.getActiveFlatKwh().multiply(new BigDecimal(price.getFlat())); + ammeterRevenue.setDataTime(dateTime); + if (CollectionUtils.isEmpty(ammeterList) || CollectionUtils.isEmpty(priceList)) { + return ammeterRevenue; } + if (SiteEnum.FX.getCode().equals(siteId)) { + for (AmmeterStatisListVo ammeter : ammeterList) { + for (EnergyPriceConfigVo priceConfig : priceList) { + if (isInTimeRange(priceConfig.getStartTime(), priceConfig.getEndTime(), ammeter.getTimePart())) { + calculateByCostType(ammeter, priceConfig, ammeterRevenue); + } + } + } + } else { + // 其他站点暂时默认与电动所内部一致处理,按天计算逻辑 + AmmeterStatisListVo ammeter = ammeterList.get(0); + EnergyPriceConfigVo price = priceList.get(0); + ammeterRevenue.setActivePeakPrice(ammeter.getActivePeakKwh().multiply(price.getPeak())); + ammeterRevenue.setActiveHighPrice(ammeter.getActiveHighKwh().multiply(price.getHigh())); + ammeterRevenue.setActiveFlatPrice(ammeter.getActiveFlatKwh().multiply(price.getFlat())); + ammeterRevenue.setActiveValleyPrice(ammeter.getActiveValleyKwh().multiply(price.getValley())); + ammeterRevenue.setReActivePeakPrice(ammeter.getReActivePeakKwh().multiply(price.getPeak())); + ammeterRevenue.setReActiveHighPrice(ammeter.getReActiveHighKwh().multiply(price.getHigh())); + ammeterRevenue.setReActiveFlatPrice(ammeter.getReActiveFlatKwh().multiply(price.getFlat())); + ammeterRevenue.setReActiveValleyPrice(ammeter.getReActiveValleyKwh().multiply(price.getValley())); + } + ammeterRevenue.setActiveTotalPrice(ammeterRevenue.getActivePeakPrice().add(ammeterRevenue.getActiveHighPrice()).add(ammeterRevenue.getActiveFlatPrice()).add(ammeterRevenue.getActiveValleyPrice())); + ammeterRevenue.setReActiveTotalPrice(ammeterRevenue.getReActivePeakPrice().add(ammeterRevenue.getReActiveHighPrice()).add(ammeterRevenue.getReActiveFlatPrice()).add(ammeterRevenue.getReActiveValleyPrice())); return ammeterRevenue; } + private static boolean isInTimeRange(String startTimeStr, String endTimeStr, String timePartStr) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + // 解析时间字符串为LocalTime对象 + LocalTime checkTime = LocalTime.parse(timePartStr, formatter); + // 定义时间范围 + LocalTime startTime = LocalTime.parse(startTimeStr, formatter); + LocalTime endTime = LocalTime.parse(endTimeStr, formatter); + // 判断时间是否在指定范围内 + return checkTime.compareTo(startTime) >= 0 + && checkTime.compareTo(endTime) < 0; + } + + private static void calculateByCostType(AmmeterStatisListVo ammeter, EnergyPriceConfigVo priceConfig, AmmeterRevenueStatisListVo ammeterRevenue) { + switch (CostType.getEnumByCode(priceConfig.getCostType())) { + case PEAK: + ammeterRevenue.setActivePeakPrice(ammeterRevenue.getActivePeakPrice().add(ammeter.getActiveTotalKwh().multiply(priceConfig.getPeak()))); + ammeterRevenue.setReActivePeakPrice(ammeterRevenue.getReActivePeakPrice().add(ammeter.getReActiveTotalKwh().multiply(priceConfig.getPeak()))); + break; + case HIGH: + ammeterRevenue.setActiveHighPrice(ammeterRevenue.getActiveHighPrice().add(ammeter.getActiveTotalKwh().multiply(priceConfig.getHigh()))); + ammeterRevenue.setReActiveHighPrice(ammeterRevenue.getReActiveHighPrice().add(ammeter.getReActiveTotalKwh().multiply(priceConfig.getHigh()))); + break; + case FLAT: + ammeterRevenue.setActiveFlatPrice(ammeterRevenue.getActiveFlatPrice().add(ammeter.getActiveTotalKwh().multiply(priceConfig.getFlat()))); + ammeterRevenue.setReActiveFlatPrice(ammeterRevenue.getReActiveFlatPrice().add(ammeter.getReActiveTotalKwh().multiply(priceConfig.getFlat()))); + break; + case VALLEY: + ammeterRevenue.setActiveValleyPrice(ammeterRevenue.getActiveValleyPrice().add(ammeter.getActiveTotalKwh().multiply(priceConfig.getValley()))); + ammeterRevenue.setReActiveValleyPrice(ammeterRevenue.getReActiveValleyPrice().add(ammeter.getReActiveTotalKwh().multiply(priceConfig.getValley()))); + break; + default: + break; + } + } + + private static List generateTargetDates(String startDateStr, String endDateStr) { + // 定义日期格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + // 解析日期字符串 + LocalDate startDate = LocalDate.parse(startDateStr, formatter); + LocalDate endDate = LocalDate.parse(endDateStr, formatter); + + List targetDates = new ArrayList<>(); + targetDates.add(startDate); // 添加起始日期 + while (startDate.isBefore(endDate)) { + startDate = startDate.plusDays(1); // 递增1天 + targetDates.add(startDate); // 添加递增后的日期 + } + return targetDates; + } + private void dealWithAmmeterTotalDate(AmmeterStatisListVo ammeterStatisListVo, AmmeterStatisListVo totalVo) { // 有功 totalVo.setActiveTotalKwh(totalVo.getActiveTotalKwh().add(ammeterStatisListVo.getActiveTotalKwh())); diff --git a/ems-system/src/main/resources/mapper/ems/EmsAmmeterDataMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsAmmeterDataMapper.xml index f49a05a..f679965 100644 --- a/ems-system/src/main/resources/mapper/ems/EmsAmmeterDataMapper.xml +++ b/ems-system/src/main/resources/mapper/ems/EmsAmmeterDataMapper.xml @@ -1061,4 +1061,83 @@ and device_id = #{deviceId} ORDER BY data_update_time DESC LIMIT 1 + + \ No newline at end of file diff --git a/ems-system/src/main/resources/mapper/ems/EmsEnergyPriceConfigMapper.xml b/ems-system/src/main/resources/mapper/ems/EmsEnergyPriceConfigMapper.xml index 534389d..68823f9 100644 --- a/ems-system/src/main/resources/mapper/ems/EmsEnergyPriceConfigMapper.xml +++ b/ems-system/src/main/resources/mapper/ems/EmsEnergyPriceConfigMapper.xml @@ -177,18 +177,41 @@ where t.`year` = #{currentYear} and t.`month` = #{currentMonth} - + select + epc.yearMonth as yearMonth, + epc.peak, + epc.high, + epc.flat, + epc.valley, + eptc.start_time as startTime, + eptc.end_time as endTime, + eptc.cost_type as costType + from + ( + select + id, site_id, peak, high, flat, valley, + CONCAT(year, '-', LPAD(month, 2, '0')) as yearMonth, + STR_TO_DATE(CONCAT(year, '-', month, '-01'), '%Y-%m-%d') as dateTime + from ems_energy_price_config + where 1 = 1 + + and site_id = #{siteId} + + order by year, month + ) epc + left join ems_price_time_config eptc on eptc.price_id = epc.id - - and site_id = #{siteId} - - - and STR_TO_DATE(CONCAT(year, '-', month, '-01'), '%Y-%m-%d') between #{startTime} and #{endTime} + + ( + (#{startDate} between dateTime and LAST_DAY(dateTime)) + or + ( #{endDate} between dateTime and LAST_DAY(dateTime)) + or + (dateTime between #{startDate} and #{endDate}) + ) - order by - `year` asc, - `month` desc; + order by epc.yearMonth, eptc.start_time \ No newline at end of file