package com.doumee.service.business.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.doumee.core.constants.ResponseStatus;
|
import com.doumee.core.exception.BusinessException;
|
import com.doumee.core.utils.Constants;
|
import com.doumee.core.utils.DateUtil;
|
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.time.format.DateTimeParseException;
|
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);
|
return buildElectricalDailyStats(start, end);
|
}
|
|
@Override
|
public String refreshElectricalDailyStatsForRange(String readTimeBegin, String readTimeEnd) {
|
if (StringUtils.isBlank(readTimeBegin) || StringUtils.isBlank(readTimeEnd)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "抄表时间段不能为空");
|
}
|
LocalDate start = parseDateTime(readTimeBegin.trim()).minusDays(1);
|
LocalDate end = parseDateTime(readTimeEnd.trim()).plusDays(1);
|
if (start.isAfter(end)) {
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "抄表时间段无效");
|
}
|
buildElectricalDailyStats(start, end);
|
return "已刷新每日电量/电费统计(" + start.format(DATE_FMT) + " ~ " + end.format(DATE_FMT) + ")";
|
}
|
|
@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 List<DailyEnergyStatVO> buildElectricalDailyStats(LocalDate start, LocalDate end) {
|
LocalDate queryStart = start.minusDays(1L);
|
Map<String, DailyEnergyStatVO> bucket = initDailyBucket(start, end);
|
List<YwElectricalData> rows = loadElectricalRowsForStats(queryStart, end);
|
|
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);
|
}
|
|
private List<YwElectricalData> loadElectricalRowsForStats(LocalDate queryStart, LocalDate end) {
|
String queryStartStr = queryStart.format(DATE_FMT) + " 00:00:00";
|
String queryEndStr = end.format(DATE_FMT) + " 23:59:59";
|
return ywElectricalDataMapper.selectList(new QueryWrapper<YwElectricalData>().lambda()
|
.eq(YwElectricalData::getIsdeleted, Constants.ZERO)
|
.and(w -> w.and(w1 -> w1.isNotNull(YwElectricalData::getAddTime)
|
.ne(YwElectricalData::getAddTime, "")
|
.ge(YwElectricalData::getAddTime, queryStartStr)
|
.le(YwElectricalData::getAddTime, queryEndStr))
|
.or(w2 -> w2.and(w3 -> w3.isNull(YwElectricalData::getAddTime)
|
.or().eq(YwElectricalData::getAddTime, ""))
|
.ge(YwElectricalData::getCreateDate, java.sql.Date.valueOf(queryStart))
|
.le(YwElectricalData::getCreateDate, java.sql.Date.valueOf(end.plusDays(1))))));
|
}
|
|
private static LocalDate parseDateTime(String text) {
|
if (text.length() >= 10) {
|
try {
|
return LocalDate.parse(text.substring(0, 10), DATE_FMT);
|
} catch (DateTimeParseException ignored) {
|
}
|
}
|
try {
|
Date date = DateUtil.StringToDate(text, READ_TIME_PATTERN);
|
if (date != null) {
|
return date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate();
|
}
|
} catch (Exception ignored) {
|
}
|
throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "抄表时间格式不正确");
|
}
|
|
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;
|
}
|
}
|
}
|