ソースを参照

refactor(infrared): 优化用电量统计方法

- 重构 getDailyAndTotalElectricityAsMap 方法,优化数据查询和处理逻辑- 使用 Wrappers.lambdaQuery()替代 new LambdaQueryWrapper<>,提高代码可读性
-通过批量查询公司信息,解决 N+1 查询问题,提升性能- 优化当日用电量计算逻辑,排除异常数据
- 对结果进行排序,提高数据展示的一致性
林仔 8 ヶ月 前
コミット
977f858688

+ 55 - 59
infrared-reading-meter-service/src/main/java/com/zksy/infrared/service/impl/InfraredReadingMeterServiceImpl.java

@@ -1,6 +1,7 @@
 package com.zksy.infrared.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.zksy.common.exception.CommonException;
 import com.zksy.infrared.domain.CompanyElectric;
@@ -407,88 +408,83 @@ public class InfraredReadingMeterServiceImpl extends ServiceImpl<InfraredReading
     }
     @Override
     public List<Map<String, Object>> 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<InfraredReadingMeter> allMeterQuery = new LambdaQueryWrapper<>();
-        allMeterQuery.isNotNull(InfraredReadingMeter::getElectricNumber)
-                .isNotNull(InfraredReadingMeter::getElectricEnergy)
-                .groupBy(InfraredReadingMeter::getElectricNumber); // 去重获取所有电表号
-        List<String> allValidMeterNumbers = list(allMeterQuery).stream()
-                .map(InfraredReadingMeter::getElectricNumber)
-                .filter(Objects::nonNull)
-                .filter(num -> !num.trim().isEmpty())
-                .collect(Collectors.toList());
-
-        // 查询当日所有有效记录(用于计算当日用电量)
-        LambdaQueryWrapper<InfraredReadingMeter> todayQuery = new LambdaQueryWrapper<>();
-        todayQuery.between(InfraredReadingMeter::getCreateTime, startOfDay, endOfDay)
-                .isNotNull(InfraredReadingMeter::getElectricNumber)
-                .isNotNull(InfraredReadingMeter::getElectricEnergy)
-                .orderByAsc(InfraredReadingMeter::getCreateTime);
-        List<InfraredReadingMeter> todayRecords = list(todayQuery);
+        LambdaQueryWrapper<InfraredReadingMeter> baseQuery = Wrappers.lambdaQuery();
+        baseQuery.isNotNull(InfraredReadingMeter::getElectricNumber) // 过滤无效电表号
+                .isNotNull(InfraredReadingMeter::getElectricEnergy)  // 过滤无效电量
+                .ge(InfraredReadingMeter::getElectricEnergy, 0);    // 排除负数异常数据
+        List<InfraredReadingMeter> allValidRecords = list(baseQuery);
 
-        // 按电表号分组存储当日记录
-        Map<String, List<InfraredReadingMeter>> todayRecordsByMeter = todayRecords.stream()
+        // 按电表号分组,处理数据(减少循环次数)
+        Map<String, List<InfraredReadingMeter>> recordsByMeter = allValidRecords.stream()
                 .collect(Collectors.groupingBy(InfraredReadingMeter::getElectricNumber));
 
-        // 查询所有电表的最新总电量记录
-        LambdaQueryWrapper<InfraredReadingMeter> latestQuery = new LambdaQueryWrapper<>();
-        latestQuery.isNotNull(InfraredReadingMeter::getElectricNumber)
-                .isNotNull(InfraredReadingMeter::getElectricEnergy);
-        List<InfraredReadingMeter> allRecords = list(latestQuery);
-
-        // 按电表号分组,取最新记录(创建时间最晚)
-        Map<String, InfraredReadingMeter> latestRecordsByMeter = allRecords.stream()
-                .collect(Collectors.groupingBy(InfraredReadingMeter::getElectricNumber,
-                        Collectors.collectingAndThen(
-                                Collectors.maxBy(Comparator.comparing(InfraredReadingMeter::getCreateTime)),
-                                Optional::get)));
+        // 批量查询公司信息(解决N+1查询问题,性能提升显著)
+        Set<String> allMeterNumbers = recordsByMeter.keySet();
+        LambdaQueryWrapper<CompanyElectric> companyQuery = Wrappers.lambdaQuery();
+        companyQuery.in(CompanyElectric::getElectricNumber, allMeterNumbers);
+        Map<String, String> meterToCompany = companyElectricService.list(companyQuery).stream()
+                .filter(company -> company.getElectricNumber() != null)
+                .collect(Collectors.toMap(
+                        CompanyElectric::getElectricNumber,
+                        CompanyElectric::getCompanyName,
+                        (oldVal, newVal) -> newVal // 电表号重复时取最新值
+                ));
 
-        // 组装结果(保留两位小数)
+        // 组装最终结果
         List<Map<String, Object>> result = new ArrayList<>();
-        for (String electricNumber : allValidMeterNumbers) {
+        for (Map.Entry<String, List<InfraredReadingMeter>> entry : recordsByMeter.entrySet()) {
+            String electricNumber = entry.getKey();
+            List<InfraredReadingMeter> meterRecords = entry.getValue();
+
             Map<String, Object> meterMap = new HashMap<>(4);
             meterMap.put("electricNumber", electricNumber);
 
-            LambdaQueryWrapper<CompanyElectric> companyElectricQuery = new LambdaQueryWrapper<>();
-            companyElectricQuery.eq(CompanyElectric::getElectricNumber, electricNumber);
-            CompanyElectric companyElectric = companyElectricService.getOne(companyElectricQuery);
-            meterMap.put("companyName", companyElectric == null ? "" : companyElectric.getCompanyName());
+            // 关联公司名称(默认空字符串,避免空指针)
+            String companyName = meterToCompany.getOrDefault(electricNumber, "");
+            meterMap.put("companyName", companyName);
 
-            // 获取该电表的最新总电量(保留两位小数)
-            InfraredReadingMeter latestRecord = latestRecordsByMeter.get(electricNumber);
-            if (latestRecord == null || latestRecord.getElectricEnergy() == null) {
-                continue; // 排除总电量为空的电表
+            // 计算累计总电量(取该电表最新一条记录的电量)
+            InfraredReadingMeter latestRecord = meterRecords.stream()
+                    .max(Comparator.comparing(InfraredReadingMeter::getCreateTime)) // 按时间取最新
+                    .orElse(null);
+            BigDecimal totalElectricity = BigDecimal.ZERO.setScale(2);
+            if (latestRecord != null) {
+                totalElectricity = BigDecimal.valueOf(latestRecord.getElectricEnergy())
+                        .setScale(2, RoundingMode.HALF_UP); // 四舍五入保留两位小数
             }
-            BigDecimal totalElectricity = BigDecimal.valueOf(latestRecord.getElectricEnergy())
-                    .setScale(2, RoundingMode.HALF_UP); // 四舍五入保留两位小数
             meterMap.put("totalElectricity", totalElectricity);
 
-            // 计算当日用电量(无数据则为0,保留两位小数)
-            List<InfraredReadingMeter> 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)
+            //计算当日用电量
+            List<InfraredReadingMeter> todayRecords = meterRecords.stream()
+                    .filter(record -> record.getCreateTime().after(startOfDay)
+                            && record.getCreateTime().before(endOfDay)) // 筛选当日记录
+                    .sorted(Comparator.comparing(InfraredReadingMeter::getCreateTime)) // 按时间排序
+                    .collect(Collectors.toList());
+
+            BigDecimal dailyElectricity = BigDecimal.ZERO.setScale(2);
+            if (todayRecords.size() >= 2) {
+                InfraredReadingMeter firstRecord = todayRecords.get(0); // 当日第一条记录
+                InfraredReadingMeter lastRecord = todayRecords.get(todayRecords.size() - 1); // 当日最后一条
+                double firstEnergy = firstRecord.getElectricEnergy();
+                double lastEnergy = lastRecord.getElectricEnergy();
+
+                // 排除异常:若首次电量>末次电量(如电表复位),当日用电量设为0
+                if (lastEnergy >= firstEnergy) {
+                    dailyElectricity = BigDecimal.valueOf(lastEnergy - firstEnergy)
                             .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);
         }
-
+        // 按电表号排序
+        result.sort(Comparator.comparing(map -> (String) map.get("electricNumber")));
         return result;
     }
 }