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<DailyEnergyStatVO> electricalDailyStats() {
|
LocalDate end = LocalDate.now();
|
LocalDate start = end.minusDays(DAYS - 1L);
|
LocalDate queryStart = start.minusDays(1L);
|
Map<String, DailyEnergyStatVO> bucket = initDailyBucket(start, end);
|
|
List<YwElectricalData> rows = ywElectricalDataMapper.selectList(new QueryWrapper<YwElectricalData>().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<String, Map<String, MeterDayReading>> 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<String, MeterDayReading> 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<DailyEnergyStatVO> conditionerDailyStats() {
|
LocalDate end = LocalDate.now();
|
LocalDate start = end.minusDays(DAYS - 1L);
|
Map<String, DailyEnergyStatVO> bucket = initDailyBucket(start, end);
|
|
List<YwConditionerUsage> rows = ywConditionerUsageMapper.selectList(new QueryWrapper<YwConditionerUsage>().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<String, Map<String, MeterDayReading>> meterDayLatest,
|
String meterKey,
|
String dayKey,
|
MeterDayReading snapshot) {
|
Map<String, MeterDayReading> 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<DailyEnergyStatVO> normalizeBucket(Map<String, DailyEnergyStatVO> bucket) {
|
List<DailyEnergyStatVO> 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<String, DailyEnergyStatVO> initDailyBucket(LocalDate start, LocalDate end) {
|
Map<String, DailyEnergyStatVO> 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;
|
}
|
}
|
}
|