Procházet zdrojové kódy

能耗接口报错修复、优化

fuyuchuan před 9 hodinami
rodič
revize
f66e9fa042

+ 4 - 4
service-ems/service-ems-biz/src/main/java/com/usky/ems/domain/EmsEnergyItemCode.java

@@ -35,10 +35,10 @@ public class EmsEnergyItemCode implements Serializable {
     private Integer energyType;
     @TableField("updated_by")
     private Long updatedBy;
-    @TableField("update_time")
-    private LocalDateTime updateTime;
+    // @TableField("update_time")
+    // private LocalDateTime updateTime;
     @TableField("created_by")
     private Long createdBy;
-    @TableField("create_time")
-    private LocalDateTime createTime;
+    // @TableField("create_time")
+    // private LocalDateTime createTime;
 }

+ 193 - 88
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/impl/EmsAnalysisServiceImpl.java

@@ -23,6 +23,7 @@ import com.usky.ems.mapper.EmsEnergyItemCodeMapper;
 import com.usky.ems.service.EmsAnalysisService;
 import com.usky.ems.service.TdengineService;
 import com.usky.ems.service.vo.*;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.util.StringUtils;
@@ -36,6 +37,7 @@ import java.sql.ResultSet;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.YearMonth;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
@@ -43,6 +45,7 @@ import java.util.stream.Collectors;
 /**
  * 能耗分析服务实现
  */
+@Slf4j
 @Service
 @DS("mysql")
 public class EmsAnalysisServiceImpl implements EmsAnalysisService {
@@ -1026,126 +1029,228 @@ public class EmsAnalysisServiceImpl implements EmsAnalysisService {
                 resp.setEnergyTypeName(id >= 1 && id <= 3 ? ENERGY_TYPE_NAMES[(int) id] : "");
             }
 
-            // 设置时间维度
-            resp.setDimension(request.getTimeDimension());
-
-            // 为每个设备查询对比数据
-            List<EmsCompareSeriesItemVO> series = new ArrayList<>();
-
-            for (String deviceId : request.getDeviceIds()) {
-                EmsCompareSeriesItemVO seriesItem = getDeviceCompareData(deviceId, request.getEnergyTypeId(),
-                        request.getTimeDimension(), request.getTimeValues());
-                if (seriesItem != null) {
-                    series.add(seriesItem);
-                }
-            }
+            // 根据查询类型和起止时间生成完整时间轴
+            List<String> timeSeries = generateCompareTimeSeries(request.getTimeDimension(), request.getTimeValues());
+            resp.setTimeDimension(request.getTimeDimension());
+            resp.setDimension(timeSeries);
 
+            // 批量查询设备历史数据并按时间轴计算对比值
+            List<EmsCompareSeriesItemVO> series = buildCompareSeries(
+                    request.getDeviceIds(), request.getTimeDimension(), timeSeries);
             resp.setSeries(series);
 
         } catch (Exception e) {
-            System.err.println("Error getting compare data: " + e.getMessage());
+            log.warn("获取对比数据异常: {}", e.getMessage(), e);
         }
 
         return resp;
     }
 
     /**
-     * 获取设备对比数据
+     * 根据查询类型(日/月/年)和起止时间,生成完整时间序列
      */
-    private EmsCompareSeriesItemVO getDeviceCompareData(String deviceId, Long energyTypeId, String timeDimension, List<String> timeValues) {
-        try (Connection conn = mysqlDataSource.getConnection()) {
-            // 获取设备名称
-            String deviceName = getDeviceName(deviceId, conn);
-
-            List<EmsCompareValueVO> values = new ArrayList<>();
-
-            // 为每个时间点查询数据
-            for (String timeValue : timeValues) {
-                String[] timeRange = getTimeRange(timeDimension, timeValue);
-                BigDecimal usage = queryDeviceEnergyForCompare(deviceId, energyTypeId, timeRange[0], timeRange[1], conn);
+    private List<String> generateCompareTimeSeries(String timeDimension, List<String> timeValues) {
+        if (timeValues == null || timeValues.isEmpty()) {
+            return new ArrayList<>();
+        }
+        String start = timeValues.get(0).trim();
+        String end = (timeValues.size() > 1 ? timeValues.get(timeValues.size() - 1) : start).trim();
+        if (start.isEmpty()) {
+            return new ArrayList<>();
+        }
+        if (end.isEmpty()) {
+            end = start;
+        }
 
-                EmsCompareValueVO valueItem = new EmsCompareValueVO();
-                valueItem.setTimeValue(timeValue);
-                valueItem.setUsage(usage.setScale(2, RoundingMode.HALF_UP));
-                values.add(valueItem);
+        try {
+            switch (timeDimension.toUpperCase()) {
+                case "D":
+                    return generateDailyRange(start, end);
+                case "M":
+                    return generateMonthlyRange(start, end);
+                case "Y":
+                    return generateYearlyRange(start, end);
+                default:
+                    return new ArrayList<>(timeValues);
             }
+        } catch (Exception e) {
+            log.warn("生成对比时间序列失败: timeDimension={}, timeValues={}", timeDimension, timeValues, e);
+            return new ArrayList<>(timeValues);
+        }
+    }
 
-            EmsCompareSeriesItemVO seriesItem = new EmsCompareSeriesItemVO();
-            seriesItem.setDeviceId(deviceId);
-            seriesItem.setDeviceName(deviceName);
-            seriesItem.setValues(values);
-
-            return seriesItem;
+    private List<String> generateDailyRange(String start, String end) {
+        List<String> points = new ArrayList<>();
+        LocalDate startDate = LocalDate.parse(start, DateTimeFormatter.ISO_LOCAL_DATE);
+        LocalDate endDate = LocalDate.parse(end, DateTimeFormatter.ISO_LOCAL_DATE);
+        if (endDate.isBefore(startDate)) {
+            LocalDate tmp = startDate;
+            startDate = endDate;
+            endDate = tmp;
+        }
+        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE;
+        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
+            points.add(date.format(formatter));
+        }
+        return points;
+    }
 
-        } catch (Exception e) {
-            System.err.println("Error getting device compare data: " + e.getMessage());
-            return null;
+    private List<String> generateMonthlyRange(String start, String end) {
+        List<String> points = new ArrayList<>();
+        YearMonth startMonth = YearMonth.parse(start, DateTimeFormatter.ofPattern("yyyy-MM"));
+        YearMonth endMonth = YearMonth.parse(end, DateTimeFormatter.ofPattern("yyyy-MM"));
+        if (endMonth.isBefore(startMonth)) {
+            YearMonth tmp = startMonth;
+            startMonth = endMonth;
+            endMonth = tmp;
+        }
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
+        for (YearMonth month = startMonth; !month.isAfter(endMonth); month = month.plusMonths(1)) {
+            points.add(month.format(formatter));
         }
+        return points;
     }
 
-    /**
-     * 获取设备名称
-     */
-    private String getDeviceName(String deviceId, Connection conn) {
-        try {
-            String sql = "SELECT name FROM ems_device WHERE id = ?";
-            try (PreparedStatement stmt = conn.prepareStatement(sql)) {
-                stmt.setString(1, deviceId);
-                try (ResultSet rs = stmt.executeQuery()) {
-                    if (rs.next()) {
-                        return rs.getString("name");
-                    }
-                }
-            }
-        } catch (Exception e) {
-            System.err.println("Error getting device name: " + e.getMessage());
+    private List<String> generateYearlyRange(String start, String end) {
+        List<String> points = new ArrayList<>();
+        int startYear = Integer.parseInt(start);
+        int endYear = Integer.parseInt(end);
+        if (endYear < startYear) {
+            int tmp = startYear;
+            startYear = endYear;
+            endYear = tmp;
+        }
+        for (int year = startYear; year <= endYear; year++) {
+            points.add(String.valueOf(year));
         }
-        return "未知设备";
+        return points;
     }
 
     /**
-     * 查询设备能耗(用于对比)
+     * 批量查询设备对比数据:一次拉取 TSDB 历史数据,再按时间轴分段计算用量
      */
-    private BigDecimal queryDeviceEnergyForCompare(String deviceId, Long energyTypeId, String startTime, String endTime, Connection conn) {
-        try {
-            StringBuilder sql = new StringBuilder();
-            sql.append("SELECT SUM(eed.end_value - eed.start_value) as total_usage ");
-            sql.append("FROM ems_energy_consumption_device_data eed ");
-            if (energyTypeId != null) {
-                sql.append("INNER JOIN ems_device ed ON eed.device_id = ed.id ");
-                sql.append("INNER JOIN ems_product_energy_type epe ON ed.product_id = epe.product_id ");
-            }
-            sql.append("WHERE eed.device_id = ? ");
-            sql.append("AND eed.start_time >= ? AND eed.end_time <= ? ");
-
-            if (energyTypeId != null) {
-                sql.append("AND epe.energy_type = ? ");
-            }
+    private List<EmsCompareSeriesItemVO> buildCompareSeries(List<String> deviceIds, String timeDimension,
+                                                            List<String> timeSeries) {
+        if (deviceIds == null || deviceIds.isEmpty() || timeSeries == null || timeSeries.isEmpty()) {
+            return Collections.emptyList();
+        }
 
-            try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
-                int paramIndex = 1;
-                stmt.setString(paramIndex++, deviceId);
-                stmt.setString(paramIndex++, startTime);
-                stmt.setString(paramIndex++, endTime);
+        Map<String, DmpDevice> deviceMap = loadCompareDevices(deviceIds);
+        Set<String> deviceUuids = deviceMap.values().stream()
+                .map(DmpDevice::getDeviceUuid)
+                .filter(StringUtils::hasText)
+                .map(String::trim)
+                .collect(Collectors.toCollection(LinkedHashSet::new));
 
-                if (energyTypeId != null) {
-                    stmt.setLong(paramIndex++, energyTypeId);
+        Map<String, Map<String, TreeMap<LocalDateTime, Double>>> deviceMetricData = Collections.emptyMap();
+        if (!deviceUuids.isEmpty()) {
+            String[] queryRange = getOverallCompareQueryRange(timeDimension, timeSeries);
+            deviceMetricData = queryDeviceMetricHistory(deviceUuids, queryRange[0], queryRange[1]);
+        }
+
+        List<AverageTimeSegment> segments = buildCompareTimeSegments(timeDimension, timeSeries);
+        List<EmsCompareSeriesItemVO> series = new ArrayList<>();
+        for (String deviceId : deviceIds) {
+            DmpDevice device = deviceMap.get(deviceId);
+            String deviceUuid = device != null && StringUtils.hasText(device.getDeviceUuid())
+                    ? device.getDeviceUuid().trim() : null;
+            TreeMap<LocalDateTime, Double> timeValueMap = null;
+            if (deviceUuid != null) {
+                Map<String, TreeMap<LocalDateTime, Double>> metricMap = deviceMetricData.get(deviceUuid);
+                if (metricMap != null) {
+                    timeValueMap = metricMap.get(ENERGY_METRIC);
                 }
+            }
 
-                try (ResultSet rs = stmt.executeQuery()) {
-                    if (rs.next()) {
-                        double usage = rs.getDouble("total_usage");
-                        if (!rs.wasNull()) {
-                            return new BigDecimal(usage);
-                        }
+            List<EmsCompareValueVO> values = new ArrayList<>();
+            for (AverageTimeSegment segment : segments) {
+                BigDecimal usage = BigDecimal.ZERO.setScale(USAGE_SCALE, RoundingMode.HALF_UP);
+                if (timeValueMap != null && !timeValueMap.isEmpty()) {
+                    SegmentUsageResult usageResult = calculateSegmentUsage(
+                            timeValueMap, segment.getStartInclusive(), segment.getEndExclusive());
+                    if (usageResult.isHasValidReading()) {
+                        usage = BigDecimal.valueOf(usageResult.getUsage())
+                                .setScale(USAGE_SCALE, RoundingMode.HALF_UP);
                     }
                 }
+                EmsCompareValueVO valueItem = new EmsCompareValueVO();
+                valueItem.setTimeValue(segment.getLabel());
+                valueItem.setUsage(usage);
+                values.add(valueItem);
             }
-        } catch (Exception e) {
-            System.err.println("Error querying device energy for compare: " + e.getMessage());
+
+            EmsCompareSeriesItemVO seriesItem = new EmsCompareSeriesItemVO();
+            seriesItem.setDeviceId(deviceId);
+            seriesItem.setDeviceName(device != null && StringUtils.hasText(device.getDeviceName())
+                    ? device.getDeviceName() : "未知设备");
+            seriesItem.setValues(values);
+            series.add(seriesItem);
         }
+        return series;
+    }
 
-        return BigDecimal.ZERO;
+    private Map<String, DmpDevice> loadCompareDevices(List<String> deviceIds) {
+        List<DmpDevice> devices = dmpDeviceMapper.selectList(
+                new LambdaQueryWrapper<DmpDevice>()
+                        .in(DmpDevice::getDeviceId, deviceIds)
+                        .eq(DmpDevice::getDeleteFlag, 0));
+        Map<String, DmpDevice> deviceMap = new LinkedHashMap<>();
+        for (DmpDevice device : devices) {
+            if (device != null && StringUtils.hasText(device.getDeviceId())) {
+                deviceMap.putIfAbsent(device.getDeviceId().trim(), device);
+            }
+        }
+        return deviceMap;
+    }
+
+    private String[] getOverallCompareQueryRange(String timeDimension, List<String> timeSeries) {
+        LocalDateTime[] firstSegment = resolveCompareSegmentRange(timeDimension, timeSeries.get(0));
+        LocalDateTime[] lastSegment = resolveCompareSegmentRange(timeDimension, timeSeries.get(timeSeries.size() - 1));
+        return new String[]{
+                firstSegment[0].format(DATE_TIME_FORMATTER),
+                lastSegment[1].minusSeconds(1).format(DATE_TIME_FORMATTER)
+        };
+    }
+
+    private List<AverageTimeSegment> buildCompareTimeSegments(String timeDimension, List<String> timeSeries) {
+        List<AverageTimeSegment> segments = new ArrayList<>();
+        for (String timeValue : timeSeries) {
+            LocalDateTime[] range = resolveCompareSegmentRange(timeDimension, timeValue);
+            segments.add(new AverageTimeSegment(timeValue, range[0], range[1]));
+        }
+        return segments;
+    }
+
+    /**
+     * 对比分析时间段:日=自然日,月=自然月,年=自然年
+     */
+    private LocalDateTime[] resolveCompareSegmentRange(String timeDimension, String timePoint) {
+        switch (timeDimension.toUpperCase()) {
+            case "D":
+                LocalDate day = LocalDate.parse(timePoint, DateTimeFormatter.ISO_LOCAL_DATE);
+                return new LocalDateTime[]{
+                        day.atStartOfDay(),
+                        day.plusDays(1).atStartOfDay()
+                };
+            case "M":
+                YearMonth month = YearMonth.parse(timePoint, DateTimeFormatter.ofPattern("yyyy-MM"));
+                return new LocalDateTime[]{
+                        month.atDay(1).atStartOfDay(),
+                        month.plusMonths(1).atDay(1).atStartOfDay()
+                };
+            case "Y":
+                int year = Integer.parseInt(timePoint);
+                return new LocalDateTime[]{
+                        LocalDate.of(year, 1, 1).atStartOfDay(),
+                        LocalDate.of(year + 1, 1, 1).atStartOfDay()
+                };
+            default:
+                String[] range = getTimeRange(timeDimension, timePoint);
+                return new LocalDateTime[]{
+                        parseDateTime(range[0]),
+                        parseDateTime(range[1]).plusSeconds(1)
+                };
+        }
     }
 
     @Override

+ 4 - 1
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/EmsCompareResponse.java

@@ -9,6 +9,9 @@ import java.util.List;
 public class EmsCompareResponse {
 
     private String energyTypeName;
-    private String dimension;
+    /** 查询粒度:D/M/Y */
+    private String timeDimension;
+    /** 时间轴标签,如日 2026-06-01…2026-06-25 */
+    private List<String> dimension = new ArrayList<>();
     private List<EmsCompareSeriesItemVO> series = new ArrayList<>();
 }