|
|
@@ -1,61 +1,1148 @@
|
|
|
package com.usky.ems.service.impl;
|
|
|
|
|
|
+import com.baomidou.dynamic.datasource.annotation.DS;
|
|
|
+import com.usky.ems.mapper.EmsDeviceMapper;
|
|
|
+import com.usky.ems.mapper.EmsEnergyItemCodeMapper;
|
|
|
+import com.usky.ems.mapper.EmsProjectMapper;
|
|
|
+import com.usky.ems.mapper.EmsSpaceMapper;
|
|
|
import com.usky.ems.service.EmsAnalysisService;
|
|
|
+import com.usky.ems.service.TdengineService;
|
|
|
import com.usky.ems.service.vo.*;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
+import javax.sql.DataSource;
|
|
|
import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.sql.Connection;
|
|
|
+import java.sql.PreparedStatement;
|
|
|
+import java.sql.ResultSet;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.time.ZoneId;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
|
- * 能耗分析服务实现(占位数据,后续对接时序/聚合数据)
|
|
|
+ * 能耗分析服务实现
|
|
|
*/
|
|
|
@Service
|
|
|
+@DS("mysql")
|
|
|
public class EmsAnalysisServiceImpl implements EmsAnalysisService {
|
|
|
|
|
|
private static final String[] ENERGY_TYPE_NAMES = {"", "电", "水", "气"};
|
|
|
+
|
|
|
+ // 标准煤转换系数
|
|
|
+ private static final Map<Long, BigDecimal> STANDARD_COAL_FACTORS = new HashMap<Long, BigDecimal>();
|
|
|
+ static {
|
|
|
+ STANDARD_COAL_FACTORS.put(Long.valueOf(1), new BigDecimal("0.1229")); // 电
|
|
|
+ STANDARD_COAL_FACTORS.put(Long.valueOf(2), new BigDecimal("0.0857")); // 水
|
|
|
+ STANDARD_COAL_FACTORS.put(Long.valueOf(3), new BigDecimal("0.2143")); // 气
|
|
|
+ }
|
|
|
+
|
|
|
+ // 碳排放转换系数
|
|
|
+ private static final Map<Long, BigDecimal> CARBON_EMISSION_FACTORS = new HashMap<Long, BigDecimal>();
|
|
|
+ static {
|
|
|
+ CARBON_EMISSION_FACTORS.put(Long.valueOf(1), new BigDecimal("0.7850")); // 电
|
|
|
+ CARBON_EMISSION_FACTORS.put(Long.valueOf(2), new BigDecimal("0.2600")); // 水
|
|
|
+ CARBON_EMISSION_FACTORS.put(Long.valueOf(3), new BigDecimal("0.4920")); // 气
|
|
|
+ }
|
|
|
+
|
|
|
+ // 能源单位
|
|
|
+ private static final Map<Long, String> ENERGY_UNITS = new HashMap<Long, String>();
|
|
|
+ static {
|
|
|
+ ENERGY_UNITS.put(Long.valueOf(1), "kWh"); // 电
|
|
|
+ ENERGY_UNITS.put(Long.valueOf(2), "m³"); // 水
|
|
|
+ ENERGY_UNITS.put(Long.valueOf(3), "m³"); // 气
|
|
|
+ }
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private TdengineService tdengineService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EmsProjectMapper emsProjectMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EmsSpaceMapper emsSpaceMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EmsDeviceMapper emsDeviceMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private EmsEnergyItemCodeMapper emsEnergyItemCodeMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private DataSource mysqlDataSource;
|
|
|
|
|
|
@Override
|
|
|
public EmsTrendResponse getTrend(Long projectId, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
EmsTrendResponse resp = new EmsTrendResponse();
|
|
|
resp.setTimeDimension(timeDimension);
|
|
|
resp.setTimeValue(timeValue);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取项目下的所有设备
|
|
|
+ List<String> deviceIds = getDeviceIdsByProject(projectId, energyTypeId);
|
|
|
+ if (deviceIds.isEmpty()) {
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据时间维度生成时间点
|
|
|
+ List<String> timePoints = generateTimePoints(timeDimension, timeValue);
|
|
|
+
|
|
|
+ // 查询每个时间点的能耗数据
|
|
|
+ List<EmsTrendItemVO> trendItems = new ArrayList<>();
|
|
|
+ for (String timePoint : timePoints) {
|
|
|
+ EmsTrendItemVO item = calculateTrendItem(deviceIds, timeDimension, timePoint, energyTypeId);
|
|
|
+ trendItems.add(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ resp.setTrend(trendItems);
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 日志记录错误,返回空数据
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
return resp;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 生成时间点列表
|
|
|
+ */
|
|
|
+ private List<String> generateTimePoints(String timeDimension, String timeValue) {
|
|
|
+ List<String> timePoints = new ArrayList<>();
|
|
|
+
|
|
|
+ try {
|
|
|
+ switch (timeDimension.toUpperCase()) {
|
|
|
+ case "D": // 日维度,生成该日每小时
|
|
|
+ timePoints = generateHourlyPoints(timeValue);
|
|
|
+ break;
|
|
|
+ case "M": // 月维度,生成该月每天
|
|
|
+ timePoints = generateDailyPoints(timeValue);
|
|
|
+ break;
|
|
|
+ case "Y": // 年维度,生成该年每月
|
|
|
+ timePoints = generateMonthlyPoints(timeValue);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ timePoints.add(timeValue);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 如果解析出错,返回原始时间值
|
|
|
+ timePoints.add(timeValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ return timePoints;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成日维度时间点
|
|
|
+ */
|
|
|
+ private List<String> generateDailyPoints(String yearMonth) {
|
|
|
+ List<String> days = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ String[] parts = yearMonth.split("-");
|
|
|
+ int year = Integer.parseInt(parts[0]);
|
|
|
+ int month = Integer.parseInt(parts[1]);
|
|
|
+
|
|
|
+ java.time.YearMonth ym = java.time.YearMonth.of(year, month);
|
|
|
+ int daysInMonth = ym.lengthOfMonth();
|
|
|
+
|
|
|
+ for (int day = 1; day <= daysInMonth; day++) {
|
|
|
+ days.add(year + "-" + (month < 10 ? "0" : "") + month + "-" + (day < 10 ? "0" : "") + day);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ days.add(yearMonth);
|
|
|
+ }
|
|
|
+ return days;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成月维度时间点
|
|
|
+ */
|
|
|
+ private List<String> generateMonthlyPoints(String year) {
|
|
|
+ List<String> months = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ int yearInt = Integer.parseInt(year);
|
|
|
+ for (int month = 1; month <= 12; month++) {
|
|
|
+ months.add(yearInt + "-" + (month < 10 ? "0" : "") + month);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ months.add(year);
|
|
|
+ }
|
|
|
+ return months;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成小时维度时间点
|
|
|
+ */
|
|
|
+ private List<String> generateHourlyPoints(String date) {
|
|
|
+ List<String> hours = new ArrayList<>();
|
|
|
+ try {
|
|
|
+ String[] parts = date.split("-");
|
|
|
+ int year = Integer.parseInt(parts[0]);
|
|
|
+ int month = Integer.parseInt(parts[1]);
|
|
|
+ int day = Integer.parseInt(parts[2]);
|
|
|
+
|
|
|
+ for (int hour = 0; hour < 24; hour++) {
|
|
|
+ hours.add(year + "-" + (month < 10 ? "0" : "") + month + "-" + (day < 10 ? "0" : "") + day + " " + (hour < 10 ? "0" : "") + hour + ":00:00");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ hours.add(date);
|
|
|
+ }
|
|
|
+ return hours;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算单个时间点的趋势数据
|
|
|
+ */
|
|
|
+ private EmsTrendItemVO calculateTrendItem(List<String> deviceIds, String timeDimension, String timePoint, Long energyTypeId) {
|
|
|
+ EmsTrendItemVO item = new EmsTrendItemVO();
|
|
|
+ item.setTimeLabel(timePoint);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 查询设备能耗数据
|
|
|
+ BigDecimal totalUsage = queryDeviceEnergyConsumption(deviceIds, timeDimension, timePoint, energyTypeId);
|
|
|
+
|
|
|
+ // 计算标准煤和碳排放
|
|
|
+ BigDecimal standardCoal = BigDecimal.ZERO;
|
|
|
+ BigDecimal carbonEmission = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ if (energyTypeId != null && totalUsage != null && totalUsage.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ BigDecimal coalFactor = STANDARD_COAL_FACTORS.getOrDefault(energyTypeId, BigDecimal.ZERO);
|
|
|
+ BigDecimal carbonFactor = CARBON_EMISSION_FACTORS.getOrDefault(energyTypeId, BigDecimal.ZERO);
|
|
|
+
|
|
|
+ standardCoal = totalUsage.multiply(coalFactor).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ carbonEmission = totalUsage.multiply(carbonFactor).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ item.setUsage(totalUsage != null ? totalUsage.setScale(2, RoundingMode.HALF_UP) : BigDecimal.ZERO);
|
|
|
+ item.setStandardCoal(standardCoal);
|
|
|
+ item.setCarbonEmission(carbonEmission);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 出错时设置默认值
|
|
|
+ item.setUsage(BigDecimal.ZERO);
|
|
|
+ item.setStandardCoal(BigDecimal.ZERO);
|
|
|
+ item.setCarbonEmission(BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询设备能耗消耗量
|
|
|
+ */
|
|
|
+ private BigDecimal queryDeviceEnergyConsumption(List<String> deviceIds, String timeDimension, String timePoint, Long energyTypeId) {
|
|
|
+ BigDecimal totalUsage = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ System.out.println("Querying energy for timePoint: " + timePoint + ", deviceIds: " + deviceIds + ", energyTypeId: " + energyTypeId);
|
|
|
+
|
|
|
+ try (Connection conn = mysqlDataSource.getConnection()) {
|
|
|
+ String sql = buildEnergyQuerySQL(deviceIds, timeDimension, energyTypeId != null);
|
|
|
+
|
|
|
+ System.out.println("Time range for " + timePoint + ": " + String.join(" | ", getTimeRange(timeDimension, timePoint)));
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
+ int paramIndex = 1;
|
|
|
+
|
|
|
+ // 设置设备ID参数
|
|
|
+ System.out.println("Setting device IDs:");
|
|
|
+ for (String deviceId : deviceIds) {
|
|
|
+ System.out.println(" - " + deviceId);
|
|
|
+ stmt.setString(paramIndex++, deviceId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置时间参数
|
|
|
+ String[] timeRange = getTimeRange(timeDimension, timePoint);
|
|
|
+ System.out.println("Setting time range: start=" + timeRange[0] + ", end=" + timeRange[1]);
|
|
|
+ stmt.setString(paramIndex++, timeRange[0]);
|
|
|
+ stmt.setString(paramIndex++, timeRange[1]);
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ System.out.println("Setting energyTypeId: " + energyTypeId);
|
|
|
+ stmt.setLong(paramIndex++, energyTypeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ if (rs.next()) {
|
|
|
+ double usage = rs.getDouble("total_usage");
|
|
|
+ if (!rs.wasNull()) {
|
|
|
+ totalUsage = new BigDecimal(usage);
|
|
|
+ System.out.println("Found usage: " + totalUsage + " for timePoint: " + timePoint);
|
|
|
+ } else {
|
|
|
+ System.out.println("No usage data (wasNull=true) for timePoint: " + timePoint);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ System.out.println("No result set for timePoint: " + timePoint);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error querying energy consumption for timePoint: " + timePoint);
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("Final totalUsage for " + timePoint + ": " + totalUsage);
|
|
|
+ return totalUsage;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 构建能耗查询SQL
|
|
|
+ */
|
|
|
+ private String buildEnergyQuerySQL(List<String> deviceIds, String timeDimension, boolean hasEnergyTypeFilter) {
|
|
|
+ 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 (hasEnergyTypeFilter) {
|
|
|
+ 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 IN (");
|
|
|
+
|
|
|
+ // 为每个设备ID添加占位符
|
|
|
+ for (int i = 0; i < deviceIds.size(); i++) {
|
|
|
+ if (i > 0) {
|
|
|
+ sql.append(", ");
|
|
|
+ }
|
|
|
+ sql.append("?");
|
|
|
+ }
|
|
|
+ sql.append(") ");
|
|
|
+
|
|
|
+ // 添加时间条件
|
|
|
+ sql.append("AND eed.start_time >= ? AND eed.end_time <= ? ");
|
|
|
+
|
|
|
+ if (hasEnergyTypeFilter) {
|
|
|
+ sql.append("AND epe.energy_type = ? ");
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("Generated SQL: " + sql.toString());
|
|
|
+
|
|
|
+ return sql.toString();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取时间范围
|
|
|
+ */
|
|
|
+ private String[] getTimeRange(String timeDimension, String timePoint) {
|
|
|
+ String[] range = new String[2];
|
|
|
+ try {
|
|
|
+ switch (timeDimension.toUpperCase()) {
|
|
|
+ case "D":
|
|
|
+ // 对于小时级数据,timePoint已经包含具体时间,格式为 "YYYY-MM-DD HH:00:00"
|
|
|
+ if (timePoint.contains(" ")) {
|
|
|
+ // 提取日期和时间部分,格式:YYYY-MM-DD HH
|
|
|
+ String datePart = timePoint.split(" ")[0];
|
|
|
+ String hourPart = timePoint.split(" ")[1].split(":")[0];
|
|
|
+
|
|
|
+ // 设置整小时范围:HH:00:00 到 HH:59:59
|
|
|
+ range[0] = datePart + " " + hourPart + ":00:00";
|
|
|
+ range[1] = datePart + " " + hourPart + ":59:59";
|
|
|
+ } else {
|
|
|
+ // 如果没有时间,默认为全天
|
|
|
+ range[0] = timePoint + " 00:00:00";
|
|
|
+ range[1] = timePoint + " 23:59:59";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case "M":
|
|
|
+ range[0] = timePoint + " 00:00:00";
|
|
|
+ range[1] = timePoint + " 23:59:59";
|
|
|
+ break;
|
|
|
+ case "Y":
|
|
|
+ // For yearly dimension, timePoint is in format "YYYY-MM", need full month
|
|
|
+ String[] yearMonth = timePoint.split("-");
|
|
|
+ if (yearMonth.length == 2) {
|
|
|
+ String yearPart = yearMonth[0];
|
|
|
+ String monthPart = yearMonth[1];
|
|
|
+ range[0] = yearPart + "-" + monthPart + "-01 00:00:00";
|
|
|
+ range[1] = yearPart + "-" + monthPart + "-31 23:59:59";
|
|
|
+ } else {
|
|
|
+ range[0] = timePoint + "-01-01 00:00:00";
|
|
|
+ range[1] = timePoint + "-12-31 23:59:59";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ range[0] = timePoint;
|
|
|
+ range[1] = timePoint;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ range[0] = timePoint;
|
|
|
+ range[1] = timePoint;
|
|
|
+ }
|
|
|
+
|
|
|
+ return range;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据项目ID获取设备列表
|
|
|
+ */
|
|
|
+ private List<String> getDeviceIdsByProject(Long projectId, Long energyTypeId) {
|
|
|
+ List<String> deviceIds = new ArrayList<>();
|
|
|
+ try (Connection conn = mysqlDataSource.getConnection()) {
|
|
|
+ StringBuilder sql = new StringBuilder();
|
|
|
+ sql.append("SELECT DISTINCT ed.id ");
|
|
|
+ sql.append("FROM ems_device ed ");
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ sql.append("INNER JOIN ems_product_energy_type epe ON ed.product_id = epe.product_id ");
|
|
|
+ }
|
|
|
+
|
|
|
+ sql.append("WHERE 1=1 ");
|
|
|
+
|
|
|
+ if (projectId != null) {
|
|
|
+ sql.append("AND ed.project_id = ? ");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ sql.append("AND epe.energy_type = ? ");
|
|
|
+ }
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
|
|
|
+ int paramIndex = 1;
|
|
|
+
|
|
|
+ if (projectId != null) {
|
|
|
+ System.out.println("Setting projectId parameter: " + projectId);
|
|
|
+ stmt.setLong(paramIndex++, projectId);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ System.out.println("Setting energyTypeId parameter: " + energyTypeId);
|
|
|
+ stmt.setLong(paramIndex++, energyTypeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("Device query SQL: " + sql.toString());
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ while (rs.next()) {
|
|
|
+ String deviceId = rs.getString("id");
|
|
|
+ deviceIds.add(deviceId);
|
|
|
+ System.out.println("Found device ID: " + deviceId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting device IDs: " + e.getMessage());
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("Total device IDs found: " + deviceIds.size());
|
|
|
+ return deviceIds;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public EmsTrendIndicatorsResponse getTrendIndicators(Long projectId, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
EmsTrendIndicatorsResponse resp = new EmsTrendIndicatorsResponse();
|
|
|
resp.setTimeDimension(timeDimension);
|
|
|
resp.setTimeValue(timeValue);
|
|
|
- resp.setTotalUsage(BigDecimal.ZERO);
|
|
|
- resp.setStandardCoal(BigDecimal.ZERO);
|
|
|
- resp.setCarbonEmission(BigDecimal.ZERO);
|
|
|
- resp.setAreaUsage(BigDecimal.ZERO);
|
|
|
- resp.setPerCapitaUsage(BigDecimal.ZERO);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取项目下的所有设备
|
|
|
+ List<String> deviceIds = getDeviceIdsByProject(projectId, energyTypeId);
|
|
|
+ if (deviceIds.isEmpty()) {
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算总用量
|
|
|
+ String[] timeRange = getTimeRange(timeDimension, timeValue);
|
|
|
+ BigDecimal totalUsage = queryTotalEnergyConsumption(deviceIds, timeRange[0], timeRange[1], energyTypeId);
|
|
|
+
|
|
|
+ // 计算标准煤和碳排放
|
|
|
+ BigDecimal standardCoal = BigDecimal.ZERO;
|
|
|
+ BigDecimal carbonEmission = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ if (energyTypeId != null && totalUsage.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ BigDecimal coalFactor = STANDARD_COAL_FACTORS.getOrDefault(energyTypeId, BigDecimal.ZERO);
|
|
|
+ BigDecimal carbonFactor = CARBON_EMISSION_FACTORS.getOrDefault(energyTypeId, BigDecimal.ZERO);
|
|
|
+
|
|
|
+ standardCoal = totalUsage.multiply(coalFactor).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ carbonEmission = totalUsage.multiply(carbonFactor).setScale(2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算单位面积能耗和人均能耗
|
|
|
+ Map<String, BigDecimal> areaAndPopulation = getProjectAreaAndPopulation(projectId);
|
|
|
+ BigDecimal totalArea = areaAndPopulation.get("area");
|
|
|
+ BigDecimal totalPopulation = areaAndPopulation.get("population");
|
|
|
+
|
|
|
+ BigDecimal areaUsage = BigDecimal.ZERO;
|
|
|
+ BigDecimal perCapitaUsage = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ if (totalArea.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ areaUsage = totalUsage.divide(totalArea, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (totalPopulation.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ perCapitaUsage = totalUsage.divide(totalPopulation, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 评定等级
|
|
|
+ Map<String, String> rating = calculateRating(areaUsage, energyTypeId);
|
|
|
+
|
|
|
+ resp.setTotalUsage(totalUsage.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ resp.setStandardCoal(standardCoal);
|
|
|
+ resp.setCarbonEmission(carbonEmission);
|
|
|
+ resp.setAreaUsage(areaUsage);
|
|
|
+ resp.setPerCapitaUsage(perCapitaUsage);
|
|
|
+ resp.setRating(rating);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting trend indicators: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
return resp;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询总能耗
|
|
|
+ */
|
|
|
+ private BigDecimal queryTotalEnergyConsumption(List<String> deviceIds, String startTime, String endTime, Long energyTypeId) {
|
|
|
+ BigDecimal totalUsage = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ try (Connection conn = mysqlDataSource.getConnection()) {
|
|
|
+ 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 IN (")
|
|
|
+ .append(String.join(",", Collections.nCopies(deviceIds.size(), "?")))
|
|
|
+ .append(") ");
|
|
|
+ sql.append("AND eed.start_time >= ? AND eed.end_time <= ? ");
|
|
|
|
|
|
- @Override
|
|
|
- public EmsTrendCategoryResponse getTrendCategory(Long projectId, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ sql.append("AND epe.energy_type = ? ");
|
|
|
+ }
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
|
|
|
+ int paramIndex = 1;
|
|
|
+
|
|
|
+ // 设置设备ID参数
|
|
|
+ for (String deviceId : deviceIds) {
|
|
|
+ stmt.setString(paramIndex++, deviceId);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置时间参数
|
|
|
+ stmt.setString(paramIndex++, startTime);
|
|
|
+ stmt.setString(paramIndex++, endTime);
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ stmt.setLong(paramIndex++, energyTypeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ if (rs.next()) {
|
|
|
+ double usage = rs.getDouble("total_usage");
|
|
|
+ if (!rs.wasNull()) {
|
|
|
+ totalUsage = new BigDecimal(usage);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error querying total energy consumption: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return totalUsage;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取项目总面积和总人数
|
|
|
+ */
|
|
|
+ private Map<String, BigDecimal> getProjectAreaAndPopulation(Long projectId) {
|
|
|
+ Map<String, BigDecimal> result = new HashMap<>();
|
|
|
+ result.put("area", BigDecimal.ZERO);
|
|
|
+ result.put("population", BigDecimal.ZERO);
|
|
|
+
|
|
|
+ if (projectId == null) {
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("Getting project area and population for projectId: " + projectId);
|
|
|
+
|
|
|
+ try (Connection conn = mysqlDataSource.getConnection()) {
|
|
|
+ String sql = "SELECT SUM(area) as total_area, SUM(resident_population) as total_population " +
|
|
|
+ "FROM ems_space_building " +
|
|
|
+ "WHERE space_id IN (SELECT id FROM ems_space WHERE root_id = ?)";
|
|
|
+
|
|
|
+ System.out.println("Project area SQL: " + sql);
|
|
|
+ System.out.println("Setting projectId parameter: " + projectId);
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
+ stmt.setLong(1, projectId);
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ if (rs.next()) {
|
|
|
+ double area = rs.getDouble("total_area");
|
|
|
+ double population = rs.getDouble("total_population");
|
|
|
+
|
|
|
+ result.put("area", rs.wasNull() || Double.isNaN(area) ? BigDecimal.ZERO : new BigDecimal(area));
|
|
|
+ result.put("population", rs.wasNull() || Double.isNaN(population) ? BigDecimal.ZERO : new BigDecimal(population));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting project area and population: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 计算能耗评定等级
|
|
|
+ */
|
|
|
+ private Map<String, String> calculateRating(BigDecimal areaUsage, Long energyTypeId) {
|
|
|
+ Map<String, String> rating = new HashMap<>();
|
|
|
+
|
|
|
+ // 简单的评定逻辑,可以根据实际需求调整
|
|
|
+ String level;
|
|
|
+ String description = "单位面积能耗评定";
|
|
|
+
|
|
|
+ if (energyTypeId == null) {
|
|
|
+ level = "良好";
|
|
|
+ } else {
|
|
|
+ switch (energyTypeId.intValue()) {
|
|
|
+ case 1: // 电
|
|
|
+ if (areaUsage.compareTo(new BigDecimal("10")) < 0) {
|
|
|
+ level = "优秀";
|
|
|
+ } else if (areaUsage.compareTo(new BigDecimal("20")) < 0) {
|
|
|
+ level = "良好";
|
|
|
+ } else if (areaUsage.compareTo(new BigDecimal("30")) < 0) {
|
|
|
+ level = "一般";
|
|
|
+ } else {
|
|
|
+ level = "较差";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 2: // 水
|
|
|
+ if (areaUsage.compareTo(new BigDecimal("2")) < 0) {
|
|
|
+ level = "优秀";
|
|
|
+ } else if (areaUsage.compareTo(new BigDecimal("5")) < 0) {
|
|
|
+ level = "良好";
|
|
|
+ } else if (areaUsage.compareTo(new BigDecimal("8")) < 0) {
|
|
|
+ level = "一般";
|
|
|
+ } else {
|
|
|
+ level = "较差";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 3: // 气
|
|
|
+ if (areaUsage.compareTo(new BigDecimal("5")) < 0) {
|
|
|
+ level = "优秀";
|
|
|
+ } else if (areaUsage.compareTo(new BigDecimal("10")) < 0) {
|
|
|
+ level = "良好";
|
|
|
+ } else if (areaUsage.compareTo(new BigDecimal("15")) < 0) {
|
|
|
+ level = "一般";
|
|
|
+ } else {
|
|
|
+ level = "较差";
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ level = "良好";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ rating.put("level", level);
|
|
|
+ rating.put("description", description);
|
|
|
+
|
|
|
+ return rating;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有能源类型
|
|
|
+ */
|
|
|
+ private List<Long> getAllEnergyTypes(Long specificEnergyType) {
|
|
|
+ List<Long> energyTypes = new ArrayList<>();
|
|
|
+
|
|
|
+ if (specificEnergyType != null) {
|
|
|
+ energyTypes.add(specificEnergyType);
|
|
|
+ } else {
|
|
|
+ // 返回所有支持的能源类型(1:电, 2:水, 3:气)
|
|
|
+ energyTypes.addAll(Arrays.asList(1L, 2L, 3L));
|
|
|
+ }
|
|
|
+
|
|
|
+ return energyTypes;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析区域ID
|
|
|
+ */
|
|
|
+ private List<Long> parseRegionIds(String regionIds, Long projectId) {
|
|
|
+ List<Long> regionIdList = new ArrayList<>();
|
|
|
+
|
|
|
+ if (regionIds != null && !regionIds.trim().isEmpty()) {
|
|
|
+ // 解析逗号分隔的区域ID
|
|
|
+ try {
|
|
|
+ regionIdList = Arrays.stream(regionIds.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .map(new java.util.function.Function<String, Long>() {
|
|
|
+ @Override
|
|
|
+ public Long apply(String s) {
|
|
|
+ return Long.valueOf(s);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .collect(Collectors.toList());
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error parsing region IDs: " + e.getMessage());
|
|
|
+ return regionIdList;
|
|
|
+ }
|
|
|
+ } else if (projectId != null) {
|
|
|
+ // 如果没有指定区域ID,则获取项目下的所有区域
|
|
|
+ try (Connection conn = mysqlDataSource.getConnection()) {
|
|
|
+ // 查找该项目下的所有区域(type=2表示区域类型)
|
|
|
+ String sql = "SELECT id FROM ems_space WHERE root_id = ? AND type = 2";
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
+ stmt.setLong(1, projectId);
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ while (rs.next()) {
|
|
|
+ regionIdList.add(Long.valueOf(rs.getLong("id")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting region IDs by project: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return regionIdList;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分析区域能耗情况
|
|
|
+ */
|
|
|
+ private EmsRegionAnalysisItemVO analyzeRegionEnergyConsumption(Long regionId, String startTime, String endTime,
|
|
|
+ Long energyTypeId, String timeDimension, String timeValue) {
|
|
|
+ try (Connection conn = mysqlDataSource.getConnection()) {
|
|
|
+ // 获取区域基本信息
|
|
|
+ String regionName = getRegionName(regionId, conn);
|
|
|
+ if (regionName == null) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取区域面积
|
|
|
+ BigDecimal area = getRegionArea(regionId, conn);
|
|
|
+
|
|
|
+ // 获取该区域下的设备能耗
|
|
|
+ List<String> deviceIds = getDeviceIdsByRegion(regionId, energyTypeId, conn);
|
|
|
+ BigDecimal totalUsage = BigDecimal.ZERO;
|
|
|
+ String unit = "kWh";
|
|
|
+
|
|
|
+ if (!deviceIds.isEmpty()) {
|
|
|
+ totalUsage = queryTotalEnergyConsumption(deviceIds, startTime, endTime, energyTypeId);
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ unit = ENERGY_UNITS.getOrDefault(energyTypeId, "kWh");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算单位面积能耗
|
|
|
+ BigDecimal areaUsage = BigDecimal.ZERO;
|
|
|
+ if (area.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ areaUsage = totalUsage.divide(area, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ EmsRegionAnalysisItemVO item = new EmsRegionAnalysisItemVO();
|
|
|
+ item.setRegionId(regionId);
|
|
|
+ item.setRegionName(regionName);
|
|
|
+ item.setArea(area.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ item.setTotalUsage(totalUsage.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ item.setAreaUsage(areaUsage);
|
|
|
+ item.setUnit(unit);
|
|
|
+ item.setTimeDimension(timeDimension);
|
|
|
+ item.setTimeValue(timeValue);
|
|
|
+
|
|
|
+ return item;
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error analyzing region energy consumption: " + e.getMessage());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取区域名称
|
|
|
+ */
|
|
|
+ private String getRegionName(Long regionId, Connection conn) {
|
|
|
+ try {
|
|
|
+ String sql = "SELECT name FROM ems_space WHERE id = ?";
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
+ stmt.setLong(1, regionId);
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ if (rs.next()) {
|
|
|
+ return rs.getString("name");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting region name: " + e.getMessage());
|
|
|
+ }
|
|
|
+ return "未知区域";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取区域面积
|
|
|
+ */
|
|
|
+ private BigDecimal getRegionArea(Long regionId, Connection conn) {
|
|
|
+ try {
|
|
|
+ String sql = "SELECT SUM(area) as total_area FROM ems_space_building WHERE space_id = ?";
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
+ stmt.setLong(1, regionId);
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ if (rs.next()) {
|
|
|
+ double area = rs.getDouble("total_area");
|
|
|
+ if (!rs.wasNull()) {
|
|
|
+ return new BigDecimal(area);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting region area: " + e.getMessage());
|
|
|
+ }
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取区域下的设备ID列表
|
|
|
+ */
|
|
|
+ private List<String> getDeviceIdsByRegion(Long regionId, Long energyTypeId, Connection conn) {
|
|
|
+ List<String> deviceIds = new ArrayList<>();
|
|
|
+
|
|
|
+ try {
|
|
|
+ StringBuilder sql = new StringBuilder();
|
|
|
+ sql.append("SELECT DISTINCT ed.id ");
|
|
|
+ sql.append("FROM ems_device ed ");
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ sql.append("INNER JOIN ems_product_energy_type epe ON ed.product_id = epe.product_id ");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查找该区域下的建筑,然后在这些建筑中查找设备
|
|
|
+ sql.append("WHERE ed.monitoring_location IN ");
|
|
|
+ sql.append("(SELECT id FROM ems_space_building WHERE space_id = ?) ");
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ sql.append("AND epe.energy_type = ? ");
|
|
|
+ }
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
|
|
|
+ int paramIndex = 1;
|
|
|
+ stmt.setLong(paramIndex++, regionId);
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ stmt.setLong(paramIndex++, energyTypeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ while (rs.next()) {
|
|
|
+ deviceIds.add(rs.getString("id"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting device IDs by region: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return deviceIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public EmsTrendCategoryResponse getTrendCategory(Long projectId, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
EmsTrendCategoryResponse resp = new EmsTrendCategoryResponse();
|
|
|
resp.setTimeDimension(timeDimension);
|
|
|
resp.setTimeValue(timeValue);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取所有能源类型
|
|
|
+ List<Long> energyTypes = getAllEnergyTypes(energyTypeId);
|
|
|
+
|
|
|
+ // 查询每个能源类型的用量
|
|
|
+ List<EmsCategoryRatioItemVO> categoryItems = new ArrayList<>();
|
|
|
+ BigDecimal totalAllUsage = BigDecimal.ZERO;
|
|
|
+ Map<Long, BigDecimal> energyTypeUsage = new HashMap<>();
|
|
|
+
|
|
|
+ for (Long typeId : energyTypes) {
|
|
|
+ List<String> deviceIds = getDeviceIdsByProject(projectId, typeId);
|
|
|
+ if (!deviceIds.isEmpty()) {
|
|
|
+ String[] timeRange = getTimeRange(timeDimension, timeValue);
|
|
|
+ BigDecimal usage = queryTotalEnergyConsumption(deviceIds, timeRange[0], timeRange[1], typeId);
|
|
|
+ energyTypeUsage.put(typeId, usage);
|
|
|
+ totalAllUsage = totalAllUsage.add(usage);
|
|
|
+ } else {
|
|
|
+ energyTypeUsage.put(typeId, BigDecimal.ZERO);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算占比和构建响应
|
|
|
+ for (Long typeId : energyTypes) {
|
|
|
+ BigDecimal usage = energyTypeUsage.get(typeId);
|
|
|
+ BigDecimal ratio = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ if (totalAllUsage.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ ratio = usage.divide(totalAllUsage, 4, RoundingMode.HALF_UP)
|
|
|
+ .multiply(new BigDecimal("100"))
|
|
|
+ .setScale(1, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ EmsCategoryRatioItemVO item = new EmsCategoryRatioItemVO();
|
|
|
+ item.setEnergyTypeName(typeId >= 1 && typeId <= 3 ? ENERGY_TYPE_NAMES[typeId.intValue()] : "未知");
|
|
|
+ item.setRatio(ratio);
|
|
|
+ item.setUsage(usage.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ item.setUnit(ENERGY_UNITS.get(typeId));
|
|
|
+
|
|
|
+ categoryItems.add(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ resp.setCategoryRatio(categoryItems);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting trend category: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
return resp;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public EmsRegionAnalysisResponse getRegionAnalysis(Long projectId, String regionIds, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
- return new EmsRegionAnalysisResponse();
|
|
|
- }
|
|
|
+ @Override
|
|
|
+ public EmsRegionAnalysisResponse getRegionAnalysis(Long projectId, String regionIds, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
+ EmsRegionAnalysisResponse resp = new EmsRegionAnalysisResponse();
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 简化实现:如果没有指定区域ID,返回项目整体数据作为一个区域
|
|
|
+ List<EmsRegionAnalysisItemVO> items = new ArrayList<>();
|
|
|
+ String[] timeRange = getTimeRange(timeDimension, timeValue);
|
|
|
+
|
|
|
+ // 获取项目下的所有设备
|
|
|
+ List<String> deviceIds = getDeviceIdsByProject(projectId, energyTypeId);
|
|
|
+ if (!deviceIds.isEmpty()) {
|
|
|
+ // 计算项目总体能耗
|
|
|
+ BigDecimal totalUsage = queryTotalEnergyConsumption(deviceIds, timeRange[0], timeRange[1], energyTypeId);
|
|
|
+
|
|
|
+ // 获取项目面积
|
|
|
+ Map<String, BigDecimal> areaAndPopulation = getProjectAreaAndPopulation(projectId);
|
|
|
+ BigDecimal totalArea = areaAndPopulation.get("area");
|
|
|
+
|
|
|
+ // 计算单位面积能耗
|
|
|
+ BigDecimal areaUsage = BigDecimal.ZERO;
|
|
|
+ if (totalArea.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ areaUsage = totalUsage.divide(totalArea, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置单位
|
|
|
+ String unit = "kWh";
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ unit = ENERGY_UNITS.getOrDefault(energyTypeId, "kWh");
|
|
|
+ }
|
|
|
+
|
|
|
+ EmsRegionAnalysisItemVO item = new EmsRegionAnalysisItemVO();
|
|
|
+ item.setRegionId(projectId != null ? projectId : 1L);
|
|
|
+ item.setRegionName(projectId != null ? "项目" + projectId : "默认项目");
|
|
|
+ item.setArea(totalArea.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ item.setTotalUsage(totalUsage.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ item.setAreaUsage(areaUsage);
|
|
|
+ item.setUnit(unit);
|
|
|
+ item.setTimeDimension(timeDimension);
|
|
|
+ item.setTimeValue(timeValue);
|
|
|
+
|
|
|
+ items.add(item);
|
|
|
+ }
|
|
|
+
|
|
|
+ resp.setItems(items);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting region analysis: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public EmsCompareResponse getCompare(EmsCompareRequest request) {
|
|
|
EmsCompareResponse resp = new EmsCompareResponse();
|
|
|
- if (request != null && request.getEnergyTypeId() != null) {
|
|
|
- long id = request.getEnergyTypeId();
|
|
|
- resp.setEnergyTypeName(id >= 1 && id <= 3 ? ENERGY_TYPE_NAMES[(int) id] : "");
|
|
|
+
|
|
|
+ try {
|
|
|
+ if (request == null || request.getDeviceIds() == null || request.getDeviceIds().isEmpty() ||
|
|
|
+ request.getTimeValues() == null || request.getTimeValues().isEmpty()) {
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置能源类型名称
|
|
|
+ if (request.getEnergyTypeId() != null) {
|
|
|
+ long id = request.getEnergyTypeId();
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ resp.setSeries(series);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting compare data: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ EmsCompareValueVO valueItem = new EmsCompareValueVO();
|
|
|
+ valueItem.setTimeValue(timeValue);
|
|
|
+ valueItem.setUsage(usage.setScale(2, RoundingMode.HALF_UP));
|
|
|
+ values.add(valueItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ EmsCompareSeriesItemVO seriesItem = new EmsCompareSeriesItemVO();
|
|
|
+ seriesItem.setDeviceId(deviceId);
|
|
|
+ seriesItem.setDeviceName(deviceName);
|
|
|
+ seriesItem.setValues(values);
|
|
|
+
|
|
|
+ return seriesItem;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting device compare data: " + e.getMessage());
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取设备名称
|
|
|
+ */
|
|
|
+ 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());
|
|
|
+ }
|
|
|
+ return "未知设备";
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询设备能耗(用于对比)
|
|
|
+ */
|
|
|
+ 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 ");
|
|
|
}
|
|
|
- if (request != null) resp.setDimension(request.getTimeDimension());
|
|
|
+ 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 = ? ");
|
|
|
+ }
|
|
|
+
|
|
|
+ try (PreparedStatement stmt = conn.prepareStatement(sql.toString())) {
|
|
|
+ int paramIndex = 1;
|
|
|
+ stmt.setString(paramIndex++, deviceId);
|
|
|
+ stmt.setString(paramIndex++, startTime);
|
|
|
+ stmt.setString(paramIndex++, endTime);
|
|
|
+
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ stmt.setLong(paramIndex++, energyTypeId);
|
|
|
+ }
|
|
|
+
|
|
|
+ try (ResultSet rs = stmt.executeQuery()) {
|
|
|
+ if (rs.next()) {
|
|
|
+ double usage = rs.getDouble("total_usage");
|
|
|
+ if (!rs.wasNull()) {
|
|
|
+ return new BigDecimal(usage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error querying device energy for compare: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public EmsAverageResponse getAverage(Long projectId, String timeDimension, String timeValue, Long energyTypeId) {
|
|
|
+ EmsAverageResponse resp = new EmsAverageResponse();
|
|
|
+ resp.setDimension(timeDimension);
|
|
|
+ resp.setTimeValue(timeValue);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取项目下的所有设备
|
|
|
+ List<String> deviceIds = getDeviceIdsByProject(projectId, energyTypeId);
|
|
|
+ if (deviceIds.isEmpty()) {
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询总能耗
|
|
|
+ String[] timeRange = getTimeRange(timeDimension, timeValue);
|
|
|
+ BigDecimal totalUsage = queryTotalEnergyConsumption(deviceIds, timeRange[0], timeRange[1], energyTypeId);
|
|
|
+
|
|
|
+ // 获取项目面积和人口信息
|
|
|
+ Map<String, BigDecimal> areaAndPopulation = getProjectAreaAndPopulation(projectId);
|
|
|
+ BigDecimal totalArea = areaAndPopulation.get("area");
|
|
|
+ BigDecimal totalPopulation = areaAndPopulation.get("population");
|
|
|
+
|
|
|
+ // 计算单位面积能耗和人均能耗
|
|
|
+ BigDecimal areaUsage = BigDecimal.ZERO;
|
|
|
+ BigDecimal perCapitaUsage = BigDecimal.ZERO;
|
|
|
+
|
|
|
+ if (totalArea.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ areaUsage = totalUsage.divide(totalArea, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (totalPopulation.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
+ perCapitaUsage = totalUsage.divide(totalPopulation, 2, RoundingMode.HALF_UP);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置单位
|
|
|
+ String unit = "kWh";
|
|
|
+ if (energyTypeId != null) {
|
|
|
+ unit = ENERGY_UNITS.getOrDefault(energyTypeId, "kWh");
|
|
|
+ }
|
|
|
+
|
|
|
+ resp.setAreaUsage(areaUsage);
|
|
|
+ resp.setPerCapitaUsage(perCapitaUsage);
|
|
|
+ resp.setUnit(unit);
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ System.err.println("Error getting average data: " + e.getMessage());
|
|
|
+ }
|
|
|
+
|
|
|
return resp;
|
|
|
}
|
|
|
}
|