package com.doumee.service.business.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.doumee.core.utils.Constants; import com.doumee.dao.business.YwConditionerUsageMapper; import com.doumee.dao.business.YwElectricalDataMapper; import com.doumee.dao.business.model.YwConditionerUsage; import com.doumee.dao.business.model.YwElectricalData; import com.doumee.dao.business.vo.DailyEnergyStatVO; import com.doumee.service.business.YwWorkDeskEnergyService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @Service public class YwWorkDeskEnergyServiceImpl implements YwWorkDeskEnergyService { private static final int DAYS = 30; private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final String READ_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss"; @Autowired private YwElectricalDataMapper ywElectricalDataMapper; @Autowired private YwConditionerUsageMapper ywConditionerUsageMapper; @Override public List electricalDailyStats() { LocalDate end = LocalDate.now(); LocalDate start = end.minusDays(DAYS - 1L); LocalDate queryStart = start.minusDays(1L); Map bucket = initDailyBucket(start, end); List rows = ywElectricalDataMapper.selectList(new QueryWrapper().lambda() .eq(YwElectricalData::getIsdeleted, Constants.ZERO) .ge(YwElectricalData::getCreateDate, java.sql.Date.valueOf(queryStart)) .le(YwElectricalData::getCreateDate, java.sql.Date.valueOf(end.plusDays(1)))); SimpleDateFormat dayFmt = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat readTimeFmt = new SimpleDateFormat(READ_TIME_PATTERN); Map> meterDayLatest = new HashMap<>(); for (YwElectricalData row : rows) { String meterKey = resolveMeterKey(row); if (StringUtils.isBlank(meterKey)) { continue; } String dayKey = resolveElectricalDayKey(row, dayFmt); if (StringUtils.isBlank(dayKey)) { continue; } BigDecimal totalEnergy = resolveTotalEnergy(row); if (totalEnergy.compareTo(BigDecimal.ZERO) < 0) { continue; } long readingTime = resolveReadingTime(row, readTimeFmt); MeterDayReading snapshot = new MeterDayReading(totalEnergy, parseDecimal(row.getDqdj()), readingTime); upsertLatestReading(meterDayLatest, meterKey, dayKey, snapshot); } for (LocalDate day = start; !day.isAfter(end); day = day.plusDays(1)) { String todayKey = day.format(DATE_FMT); String yesterdayKey = day.minusDays(1).format(DATE_FMT); DailyEnergyStatVO stat = bucket.get(todayKey); for (Map dayReadings : meterDayLatest.values()) { MeterDayReading todayReading = dayReadings.get(todayKey); MeterDayReading yesterdayReading = dayReadings.get(yesterdayKey); if (todayReading == null || yesterdayReading == null) { continue; } BigDecimal usage = todayReading.totalEnergy.subtract(yesterdayReading.totalEnergy); if (usage.compareTo(BigDecimal.ZERO) <= 0) { continue; } stat.setTotalKwh(stat.getTotalKwh().add(usage)); stat.setTotalFee(stat.getTotalFee().add(usage.multiply(todayReading.price))); } } return normalizeBucket(bucket); } @Override public List conditionerDailyStats() { LocalDate end = LocalDate.now(); LocalDate start = end.minusDays(DAYS - 1L); Map bucket = initDailyBucket(start, end); List rows = ywConditionerUsageMapper.selectList(new QueryWrapper().lambda() .eq(YwConditionerUsage::getIsdeleted, Constants.ZERO) .ge(YwConditionerUsage::getUsageDate, java.sql.Date.valueOf(start)) .le(YwConditionerUsage::getUsageDate, java.sql.Date.valueOf(end))); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); for (YwConditionerUsage row : rows) { if (row.getUsageDate() == null) { continue; } String dayKey = sdf.format(row.getUsageDate()); if (!bucket.containsKey(dayKey)) { continue; } DailyEnergyStatVO stat = bucket.get(dayKey); stat.setTotalKwh(stat.getTotalKwh().add(nullToZero(row.getSumDl()))); stat.setTotalFee(stat.getTotalFee().add(nullToZero(row.getSumDf()))); } return normalizeBucket(bucket); } private static void upsertLatestReading(Map> meterDayLatest, String meterKey, String dayKey, MeterDayReading snapshot) { Map dayMap = meterDayLatest.computeIfAbsent(meterKey, key -> new HashMap<>()); MeterDayReading existing = dayMap.get(dayKey); if (existing == null || snapshot.readingTime >= existing.readingTime) { dayMap.put(dayKey, snapshot); } } private static String resolveMeterKey(YwElectricalData row) { if (StringUtils.isNotBlank(row.getAddress())) { return row.getAddress().trim(); } if (StringUtils.isNotBlank(row.getDeviceId())) { return "dev:" + row.getDeviceId().trim(); } if (StringUtils.isNotBlank(row.getMid())) { return "mid:" + row.getMid().trim(); } return null; } private static BigDecimal resolveTotalEnergy(YwElectricalData row) { BigDecimal total = parseDecimal(row.getZhygzdl()); if (total.compareTo(BigDecimal.ZERO) <= 0) { total = parseDecimal(row.getZyje()); } return total; } private static long resolveReadingTime(YwElectricalData row, SimpleDateFormat readTimeFmt) { if (StringUtils.isNotBlank(row.getAddTime())) { String addTime = row.getAddTime().trim(); if (addTime.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) { try { return readTimeFmt.parse(addTime).getTime(); } catch (ParseException ignored) { // fallback to createDate } } } Date createDate = row.getCreateDate(); return createDate == null ? 0L : createDate.getTime(); } private static List normalizeBucket(Map bucket) { List list = new ArrayList<>(bucket.values()); for (DailyEnergyStatVO stat : list) { stat.setTotalKwh(stat.getTotalKwh().setScale(2, RoundingMode.HALF_UP)); stat.setTotalFee(stat.getTotalFee().setScale(2, RoundingMode.HALF_UP)); } return list; } private static Map initDailyBucket(LocalDate start, LocalDate end) { Map bucket = new LinkedHashMap<>(); for (LocalDate d = start; !d.isAfter(end); d = d.plusDays(1)) { DailyEnergyStatVO vo = new DailyEnergyStatVO(); vo.setStatDate(d.format(DATE_FMT)); vo.setTotalKwh(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)); vo.setTotalFee(BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)); bucket.put(vo.getStatDate(), vo); } return bucket; } private static String resolveElectricalDayKey(YwElectricalData row, SimpleDateFormat sdf) { if (StringUtils.isNotBlank(row.getAddTime())) { String addTime = row.getAddTime().trim(); if (addTime.length() >= 10) { return addTime.substring(0, 10); } } Date createDate = row.getCreateDate(); return createDate == null ? null : sdf.format(createDate); } private static BigDecimal parseDecimal(String val) { if (StringUtils.isBlank(val)) { return BigDecimal.ZERO; } try { return new BigDecimal(val.trim()); } catch (NumberFormatException e) { return BigDecimal.ZERO; } } private static BigDecimal nullToZero(BigDecimal val) { return val == null ? BigDecimal.ZERO : val; } private static class MeterDayReading { private final BigDecimal totalEnergy; private final BigDecimal price; private final long readingTime; private MeterDayReading(BigDecimal totalEnergy, BigDecimal price, long readingTime) { this.totalEnergy = totalEnergy; this.price = price; this.readingTime = readingTime; } } }