package com.zksy.infrared.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.zksy.common.exception.CommonException; import com.zksy.infrared.domain.CompanyElectric; import com.zksy.infrared.domain.InfraredReadingMeter; import com.zksy.infrared.domain.vo.MeterDayDataVo; import com.zksy.infrared.domain.vo.MeterMonthDataVo; import com.zksy.infrared.domain.vo.MeterQuarterDataVo; import com.zksy.infrared.domain.vo.MeterYearDataVo; import com.zksy.infrared.service.CompanyElectricService; import com.zksy.infrared.service.InfraredReadingMeterService; import com.zksy.infrared.mapper.InfraredReadingMeterMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.*; import java.util.*; import java.util.stream.Collectors; /** * @author Administrator * @description 针对表【infrared_reading_meter(红外读电表数据)】的数据库操作Service实现 * @createDate 2025-06-06 10:27:47 */ @Service public class InfraredReadingMeterServiceImpl extends ServiceImpl implements InfraredReadingMeterService { // 工具方法:生成默认月数据列表 private static final List DEFAULT_MONTH_LIST = Collections.nCopies(12, BigDecimal.ZERO); // 工具方法:生成默认日数据列表 private static final List DEFAULT_DAY_LIST = Collections.nCopies(31, BigDecimal.ZERO); // 工具方法:生成默认季数据列表 private static final List DEFAULT_QUARTER_LIST = Collections.nCopies(3, new BigDecimal("0.00")); @Autowired private CompanyElectricService companyElectricService; @Override public MeterYearDataVo selectByYear(Integer year, String meterNumber) { if (year == null || year < 0 || year > 9999) { throw new CommonException("年份无效", 400); } LocalDate firstDayOfYear = LocalDate.of(year, 1, 1); LocalDate lastDayOfYear = LocalDate.of(year, 12, 31); LocalDateTime startOfDay = firstDayOfYear.atStartOfDay(); LocalDateTime endOfDay = lastDayOfYear.atTime(LocalTime.MAX); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(InfraredReadingMeter::getElectricNumber, meterNumber) .between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay) .orderByAsc(InfraredReadingMeter::getCreateTime); List list = this.list(wrapper); if (list == null || list.size() < 2) { return new MeterYearDataVo(BigDecimal.ZERO, new ArrayList<>(DEFAULT_MONTH_LIST)); } BigDecimal firstValue = BigDecimal.valueOf(list.get(0).getElectricEnergy()); BigDecimal lastValue = BigDecimal.valueOf(list.get(list.size() - 1).getElectricEnergy()); Map> groupedByMonth = list.stream() .collect(Collectors.groupingBy(item -> { LocalDate date = item.getCreateTime().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(); return date.getMonthValue(); })); List months = new ArrayList<>(groupedByMonth.keySet()); Collections.sort(months); List monthDataList = new ArrayList<>(DEFAULT_MONTH_LIST); for (int i = 0; i < months.size(); i++) { Integer currentMonth = months.get(i); List meters = groupedByMonth.get(currentMonth); if (!meters.isEmpty()) { BigDecimal start = BigDecimal.valueOf(meters.get(0).getElectricEnergy()); BigDecimal end; if (i < months.size() - 1) { Integer nextMonth = months.get(i + 1); List nextMeters = groupedByMonth.get(nextMonth); end = !nextMeters.isEmpty() ? BigDecimal.valueOf(nextMeters.get(0).getElectricEnergy()) : BigDecimal.valueOf(meters.get(meters.size() - 1).getElectricEnergy()); } else { end = BigDecimal.valueOf(meters.get(meters.size() - 1).getElectricEnergy()); } monthDataList.set(currentMonth - 1, end.subtract(start)); } } return new MeterYearDataVo(lastValue.subtract(firstValue), monthDataList); } @Override public MeterMonthDataVo selectByYearselectByYearAndMonthWithDayData(Integer year, Integer month, String meterNumber) { if (year == null || month == null || year < 0 || year > 9999 || month < 1 || month > 12) { throw new CommonException("年份或月份无效", 400); } LocalDate firstDayOfMonth = LocalDate.of(year, month, 1); LocalDate lastDayOfMonth = firstDayOfMonth.withDayOfMonth(firstDayOfMonth.lengthOfMonth()); LocalDateTime startOfDay = firstDayOfMonth.atStartOfDay(); LocalDateTime endOfDay = lastDayOfMonth.atTime(LocalTime.MAX); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(InfraredReadingMeter::getElectricNumber, meterNumber) .between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay) .orderByAsc(InfraredReadingMeter::getCreateTime); List list = this.list(wrapper); if (list == null || list.size() < 2) { return new MeterMonthDataVo(BigDecimal.ZERO, new ArrayList<>(DEFAULT_DAY_LIST)); } BigDecimal firstValue = BigDecimal.valueOf(list.get(0).getElectricEnergy()); BigDecimal lastValue = BigDecimal.valueOf(list.get(list.size() - 1).getElectricEnergy()); Map> groupedByDay = list.stream() .collect(Collectors.groupingBy(item -> { LocalDate date = item.getCreateTime().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate(); return date.getDayOfMonth(); })); List days = new ArrayList<>(groupedByDay.keySet()); Collections.sort(days); List dayDataList = new ArrayList<>(DEFAULT_DAY_LIST); for (int i = 0; i < days.size(); i++) { Integer currentDay = days.get(i); List currentMeters = groupedByDay.get(currentDay); if (!currentMeters.isEmpty()) { BigDecimal start = BigDecimal.valueOf(currentMeters.get(0).getElectricEnergy()); BigDecimal end; if (i < days.size() - 1) { Integer nextDay = days.get(i + 1); List nextMeters = groupedByDay.get(nextDay); end = !nextMeters.isEmpty() ? BigDecimal.valueOf(nextMeters.get(0).getElectricEnergy()) : BigDecimal.valueOf(currentMeters.get(currentMeters.size() - 1).getElectricEnergy()); } else { end = BigDecimal.valueOf(currentMeters.get(currentMeters.size() - 1).getElectricEnergy()); } dayDataList.set(currentDay - 1, end.subtract(start)); } } return new MeterMonthDataVo(lastValue.subtract(firstValue), dayDataList); } @Override public MeterDayDataVo selectByNewestData(String meterNumber) { if (meterNumber == null || meterNumber.isEmpty()) { throw new CommonException("电表编号不能为空", 400); } LocalDate today = LocalDate.now(); LocalDateTime startOfDay = today.atStartOfDay(); LocalDateTime endOfDay = today.atTime(LocalTime.MAX); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(InfraredReadingMeter::getElectricNumber, meterNumber) .between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay) .orderByAsc(InfraredReadingMeter::getCreateTime); List list = this.list(wrapper); if (list == null || list.size() < 2) { return new MeterDayDataVo(BigDecimal.ZERO); } BigDecimal firstValue = BigDecimal.valueOf(list.get(0).getElectricEnergy()); BigDecimal lastValue = BigDecimal.valueOf(list.get(list.size() - 1).getElectricEnergy()); return new MeterDayDataVo(lastValue.subtract(firstValue)); } @Override public MeterYearDataVo selectByCurrentYearData() { log.warn("按照年统计电表"); int currentYear = LocalDate.now().getYear(); LocalDate firstDayOfYear = LocalDate.of(currentYear, 1, 1); LocalDate lastDayOfYear = LocalDate.of(currentYear, 12, 31); LocalDateTime startOfDay = firstDayOfYear.atStartOfDay(); LocalDateTime endOfDay = lastDayOfYear.atTime(LocalTime.MAX); LambdaQueryWrapper wrapper = new LambdaQueryWrapper() .between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay) .orderByAsc(InfraredReadingMeter::getCreateTime); List list = this.list(wrapper); Map>> groupedByMonthAndMeter = list.stream() // TODO 过滤掉电表号为空、创建时间为空、总电能为空的行 .filter(item -> item.getElectricNumber() != null && !item.getElectricNumber().isEmpty() && item.getCreateTime() != null && item.getElectricEnergy() != null) .collect(Collectors.groupingBy( item -> item.getCreateTime() .toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate() .getMonthValue(), Collectors.groupingBy(InfraredReadingMeter::getElectricNumber) )); List monthDataList = new ArrayList<>(Collections.nCopies(12, BigDecimal.ZERO)); for(int month=1;month<=12;month++){ Map> meterData=groupedByMonthAndMeter.getOrDefault(month,Collections.emptyMap()); BigDecimal monthTotal=BigDecimal.ZERO; for(List meterList:meterData.values()){ if(meterList.size()>=2){ BigDecimal start = BigDecimal.valueOf(meterList.get(0).getElectricEnergy()); BigDecimal end = BigDecimal.valueOf(meterList.get(meterList.size()-1).getElectricEnergy()); monthTotal=monthTotal.add(end.subtract(start)); } } monthTotal = monthTotal.setScale(2, RoundingMode.HALF_UP); monthDataList.set(month-1,monthTotal); } BigDecimal totalElectricity = monthDataList.stream().reduce(BigDecimal.ZERO, BigDecimal::add); totalElectricity = totalElectricity.setScale(2, RoundingMode.HALF_UP); return new MeterYearDataVo(totalElectricity,monthDataList); } @Override public MeterMonthDataVo selectByCurrentYearselectByCurrentYearAndCurrentMonthWithDayData() { final List defaultDayList = Collections.nCopies(31, new BigDecimal("0.00")); LocalDate now = LocalDate.now(); int year = now.getYear(); int month = now.getMonthValue(); LocalDate firstDayOfMonth = LocalDate.of(year, month, 1); LocalDate lastDayOfMonth = firstDayOfMonth.withDayOfMonth(firstDayOfMonth.lengthOfMonth()); LocalDateTime startOfDay = firstDayOfMonth.atStartOfDay(); LocalDateTime endOfDay = lastDayOfMonth.atTime(LocalTime.MAX); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay) .orderByAsc(InfraredReadingMeter::getCreateTime); List list = this.list(wrapper); if(list==null||list.size()<2){ return new MeterMonthDataVo(new BigDecimal("0.00"),defaultDayList); } Map>> groupedByDayAndMeter=list.stream() // TODO 过滤掉电表号为空、创建时间为空、总电能为空的行 .filter(item -> item.getElectricNumber() != null && !item.getElectricNumber().isEmpty() && item.getCreateTime() != null && item.getElectricEnergy() != null) .collect(Collectors.groupingBy(item->item.getCreateTime() .toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate() .getDayOfMonth(), Collectors.groupingBy(InfraredReadingMeter::getElectricNumber))); List dayDataList=new ArrayList<>(Collections.nCopies(firstDayOfMonth.lengthOfMonth(),BigDecimal.ZERO)); for(int day=1;day<=firstDayOfMonth.lengthOfMonth();day++){ Map> meterData = groupedByDayAndMeter.getOrDefault(day, Collections.emptyMap()); BigDecimal dayTotal=BigDecimal.ZERO; for(List meterList:meterData.values()){ if(meterList.size()>=2){ BigDecimal start = BigDecimal.valueOf(meterList.get(0).getElectricEnergy()); BigDecimal end = BigDecimal.valueOf(meterList.get(meterList.size() - 1).getElectricEnergy()); dayTotal=dayTotal.add(end.subtract(start)); } } dayTotal = dayTotal.setScale(2, RoundingMode.HALF_UP); dayDataList.set(day-1,dayTotal); } Map> groupedByMeter = list.stream() // TODO 过滤掉电表号为空、创建时间为空、总电能为空的行 .filter(item -> item.getElectricNumber() != null && !item.getElectricNumber().isEmpty() && item.getCreateTime() != null && item.getElectricEnergy() != null) .collect(Collectors.groupingBy(InfraredReadingMeter::getElectricNumber)); BigDecimal totalElectricity = BigDecimal.ZERO; for (List meterList : groupedByMeter.values()) { // 找到当月最早一条数据(优化逻辑) InfraredReadingMeter firstRecord = meterList.stream() .min(Comparator.comparing(InfraredReadingMeter::getCreateTime)) .orElse(null); // 找到当月最晚一条数据(优化逻辑) InfraredReadingMeter lastRecord = meterList.stream() .max(Comparator.comparing(InfraredReadingMeter::getCreateTime)) .orElse(null); if (firstRecord != null && lastRecord != null) { BigDecimal startEnergy = BigDecimal.valueOf(firstRecord.getElectricEnergy()); BigDecimal endEnergy = BigDecimal.valueOf(lastRecord.getElectricEnergy()); totalElectricity = totalElectricity.add(endEnergy.subtract(startEnergy)); } } totalElectricity = totalElectricity.setScale(2, RoundingMode.HALF_UP); return new MeterMonthDataVo(totalElectricity,dayDataList); } @Override public MeterQuarterDataVo selectByCurrentQuarterData() { LocalDate now = LocalDate.now(); int year = now.getYear(); int month = now.getMonthValue(); int currentQuarter = (month - 1) / 3 + 1; int startMonth = (currentQuarter - 1) * 3 + 1; int endMonth = startMonth + 2; LocalDate startDate = LocalDate.of(year, startMonth, 1); LocalDate endDate = LocalDate.of(year, endMonth, YearMonth.of(year, endMonth).lengthOfMonth()); LocalDateTime startDateTime = startDate.atStartOfDay(); LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.between(InfraredReadingMeter::getCreateTime,startDateTime,endDateTime) .orderByAsc(InfraredReadingMeter::getCreateTime); List list = this.list(wrapper); if(list==null||list.size()<2){ return new MeterQuarterDataVo(new BigDecimal("0.00"),DEFAULT_QUARTER_LIST); } Map>> groupedByMonthAndMeter = list.stream() // TODO 过滤掉电表号为空、创建时间为空、总电能为空的行 .filter(item -> item.getElectricNumber() != null && !item.getElectricNumber().isEmpty() && item.getCreateTime() != null && item.getElectricEnergy() != null) .collect(Collectors.groupingBy( item -> item.getCreateTime().toInstant() .atZone(ZoneId.systemDefault()) .toLocalDate() .getMonthValue(), Collectors.groupingBy(InfraredReadingMeter::getElectricNumber) )); List monthDataList=new ArrayList<>(Collections.nCopies(3, new BigDecimal("0.00"))); BigDecimal totalQuarterElectricity = BigDecimal.ZERO; for(int m=startMonth;m<=endMonth;m++){ Map> meterData = groupedByMonthAndMeter.getOrDefault(m, Collections.emptyMap()); BigDecimal monthTotal = BigDecimal.ZERO; for(List meterList:meterData.values()){ if(meterList.size()>=2){ BigDecimal start = BigDecimal.valueOf(meterList.get(0).getElectricEnergy()); BigDecimal end = BigDecimal.valueOf(meterList.get(meterList.size() - 1).getElectricEnergy()); monthTotal=monthTotal.add(end.subtract(start)); } } monthTotal = monthTotal.setScale(2, RoundingMode.HALF_UP); monthDataList.set(m-startMonth,monthTotal); totalQuarterElectricity = totalQuarterElectricity.add(monthTotal); } totalQuarterElectricity = totalQuarterElectricity.setScale(2, RoundingMode.HALF_UP); return new MeterQuarterDataVo(totalQuarterElectricity,monthDataList); } @Override public List> getDailyAndTotalElectricityAsMap() { // 确定当日时间范围 LocalDate today = LocalDate.now(); Date startOfDay = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant()); Date endOfDay = Date.from(today.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()); // 获取所有有效的电表号(非空且有总电量记录) LambdaQueryWrapper allMeterQuery = new LambdaQueryWrapper<>(); allMeterQuery.isNotNull(InfraredReadingMeter::getElectricNumber) .isNotNull(InfraredReadingMeter::getElectricEnergy) .groupBy(InfraredReadingMeter::getElectricNumber); // 去重获取所有电表号 List allValidMeterNumbers = list(allMeterQuery).stream() .map(InfraredReadingMeter::getElectricNumber) .filter(Objects::nonNull) .filter(num -> !num.trim().isEmpty()) .collect(Collectors.toList()); // 查询当日所有有效记录(用于计算当日用电量) LambdaQueryWrapper todayQuery = new LambdaQueryWrapper<>(); todayQuery.between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay) .isNotNull(InfraredReadingMeter::getElectricNumber) .isNotNull(InfraredReadingMeter::getElectricEnergy) .orderByAsc(InfraredReadingMeter::getCreateTime); List todayRecords = list(todayQuery); // 按电表号分组存储当日记录 Map> todayRecordsByMeter = todayRecords.stream() .collect(Collectors.groupingBy(InfraredReadingMeter::getElectricNumber)); // 查询所有电表的最新总电量记录 LambdaQueryWrapper latestQuery = new LambdaQueryWrapper<>(); latestQuery.isNotNull(InfraredReadingMeter::getElectricNumber) .isNotNull(InfraredReadingMeter::getElectricEnergy); List allRecords = list(latestQuery); // 按电表号分组,取最新记录(创建时间最晚) Map latestRecordsByMeter = allRecords.stream() .collect(Collectors.groupingBy(InfraredReadingMeter::getElectricNumber, Collectors.collectingAndThen( Collectors.maxBy(Comparator.comparing(InfraredReadingMeter::getCreateTime)), Optional::get))); // 组装结果(保留两位小数) List> result = new ArrayList<>(); for (String electricNumber : allValidMeterNumbers) { Map meterMap = new HashMap<>(4); meterMap.put("electricNumber", electricNumber); LambdaQueryWrapper companyElectricQuery = new LambdaQueryWrapper<>(); companyElectricQuery.eq(CompanyElectric::getElectricNumber, electricNumber); CompanyElectric companyElectric = companyElectricService.getOne(companyElectricQuery); meterMap.put("companyName", companyElectric == null ? "" : companyElectric.getCompanyName()); // 获取该电表的最新总电量(保留两位小数) InfraredReadingMeter latestRecord = latestRecordsByMeter.get(electricNumber); if (latestRecord == null || latestRecord.getElectricEnergy() == null) { continue; // 排除总电量为空的电表 } BigDecimal totalElectricity = BigDecimal.valueOf(latestRecord.getElectricEnergy()) .setScale(2, RoundingMode.HALF_UP); // 四舍五入保留两位小数 meterMap.put("totalElectricity", totalElectricity); // 计算当日用电量(无数据则为0,保留两位小数) List todayMeterRecords = todayRecordsByMeter.getOrDefault(electricNumber, Collections.emptyList()); BigDecimal dailyElectricity; if (todayMeterRecords.size() >= 2) { InfraredReadingMeter first = todayMeterRecords.get(0); InfraredReadingMeter last = todayMeterRecords.get(todayMeterRecords.size() - 1); if (first.getElectricEnergy() != null && last.getElectricEnergy() != null) { double diff = last.getElectricEnergy() - first.getElectricEnergy(); dailyElectricity = BigDecimal.valueOf(diff) .setScale(2, RoundingMode.HALF_UP); } else { dailyElectricity = BigDecimal.ZERO.setScale(2); // 数据异常时设为0.00 } } else { dailyElectricity = BigDecimal.ZERO.setScale(2); // 当日无数据或记录不足,设为0.00 } meterMap.put("dailyElectricity", dailyElectricity); result.add(meterMap); } return result; } }