Преглед на файлове

能耗报表接口代码提交

fuyuchuan преди 5 дни
родител
ревизия
e651c777b0

+ 40 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/controller/web/EmsReportController.java

@@ -4,6 +4,7 @@ import com.usky.common.core.bean.ApiResult;
 import com.usky.ems.service.EmsReportService;
 import com.usky.ems.service.EmsModelService;
 import com.usky.ems.service.vo.*;
+import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
@@ -109,4 +110,43 @@ public class EmsReportController {
             HttpServletResponse response) {
         emsReportService.exportCollection(deviceIds, attributePointIds, timeDimension, timeValue, format, response);
     }
+
+    /**
+     * 1. 能源报表
+     * 支持按设备列表、功能点、时间类型(时/日/月/年)聚合数据
+     *
+     * @param request 能源报表请求参数
+     * @return 能源报表响应数据
+     */
+    @PostMapping("/energy")
+    @ApiOperation("能源报表")
+    public ApiResult<EnergyReportResponse> getEnergyReport(@RequestBody EnergyReportRequest request) {
+        return ApiResult.success(emsReportService.getEnergyReport(request));
+    }
+
+    /**
+     * 2. 分项报表
+     * 支持按空间ID、分项编码、日期类型统计能耗
+     *
+     * @param request 分项报表请求参数
+     * @return 分项报表响应数据
+     */
+    @PostMapping("/item")
+    @ApiOperation("分项报表")
+    public ApiResult<ItemReportResponse> getItemReport(@RequestBody ItemReportRequest request) {
+        return ApiResult.success(emsReportService.getItemReport(request));
+    }
+
+    /**
+     * 3. 区域报表
+     * 支持按区域、分项、日期类型统计能耗
+     *
+     * @param request 区域报表请求参数
+     * @return 区域报表响应数据
+     */
+    @PostMapping("/space")
+    @ApiOperation("区域报表")
+    public ApiResult<SpaceReportResponse> getSpaceReport(@RequestBody SpaceReportRequest request) {
+        return ApiResult.success(emsReportService.getSpaceReport(request));
+    }
 }

+ 24 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/EmsReportService.java

@@ -29,4 +29,28 @@ public interface EmsReportService {
     EmsEnergyStatisticsResponse getCollectionStatistics(EmsEnergyStatisticsRequest request);
 
     void exportCollection(String deviceIds, String attributePointIds, String timeDimension, String timeValue, String format, HttpServletResponse response);
+
+    /**
+     * 获取能源报表数据
+     *
+     * @param request 请求参数
+     * @return 能源报表响应
+     */
+    EnergyReportResponse getEnergyReport(EnergyReportRequest request);
+
+    /**
+     * 获取分项报表数据
+     *
+     * @param request 请求参数
+     * @return 分项报表响应
+     */
+    ItemReportResponse getItemReport(ItemReportRequest request);
+
+    /**
+     * 获取区域报表数据
+     *
+     * @param request 请求参数
+     * @return 区域报表响应
+     */
+    SpaceReportResponse getSpaceReport(SpaceReportRequest request);
 }

+ 550 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/impl/EmsReportServiceImpl.java

@@ -1,6 +1,7 @@
 package com.usky.ems.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.usky.common.core.exception.BusinessException;
 import com.usky.common.security.utils.SecurityUtils;
 import com.usky.ems.domain.DmpDevice;
 import com.usky.ems.domain.EmsDevice;
@@ -17,7 +18,11 @@ import org.springframework.util.StringUtils;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.math.BigDecimal;
 import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -29,6 +34,9 @@ public class EmsReportServiceImpl implements EmsReportService {
 
     private static final String[] ENERGY_TYPE_NAMES = {"", "电", "水", "气"};
 
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+
     @Autowired
     private DmpDeviceMapper dmpDeviceMapper;
     @Autowired
@@ -150,4 +158,546 @@ public class EmsReportServiceImpl implements EmsReportService {
             throw new RuntimeException("导出失败", e);
         }
     }
+
+    @Override
+    public EnergyReportResponse getEnergyReport(EnergyReportRequest request) {
+        if (request == null || request.getDeviceList() == null || request.getDeviceList().isEmpty()) {
+            return createEmptyEnergyReport();
+        }
+
+        // 解析时间
+        LocalDateTime startTime = parseDateTime(request.getStartTime());
+        LocalDateTime endTime = parseDateTime(request.getEndTime());
+        if (startTime == null || endTime == null) {
+            return createEmptyEnergyReport();
+        }
+
+        // 校验时间参数
+        validateTimeParams(startTime, endTime, request.getTimeType());
+
+        // 生成列定义
+        List<EnergyReportResponse.ColumnItem> columnList = generateEnergyReportColumns(request.getTimeType(), startTime, endTime);
+
+        // 生成数据列表
+        List<EnergyReportResponse.ValueItem> valueList = generateEnergyReportData(request, startTime, endTime);
+
+        EnergyReportResponse response = new EnergyReportResponse();
+        response.setColumnList(columnList);
+        response.setValueList(valueList);
+
+        return response;
+    }
+
+    @Override
+    public ItemReportResponse getItemReport(ItemReportRequest request) {
+        if (request == null || request.getItemCodes() == null || request.getItemCodes().isEmpty()) {
+            return createEmptyItemReport();
+        }
+
+        // 解析时间
+        LocalDateTime startTime = parseDateTime(request.getStartTime());
+        LocalDateTime endTime = parseDateTime(request.getEndTime());
+        if (startTime == null || endTime == null) {
+            return createEmptyItemReport();
+        }
+
+        // 校验时间参数
+        validateTimeParams(startTime, endTime, request.getDateType());
+
+        // 生成标题列
+        List<ItemReportResponse.TitleItem> titleList = generateItemReportTitles(request.getDateType(), startTime, endTime);
+
+        // 生成数据列表
+        List<Map<String, Object>> dataList = generateItemReportData(request, startTime, endTime);
+
+        ItemReportResponse response = new ItemReportResponse();
+        response.setTitleList(titleList);
+        response.setDataList(dataList);
+
+        return response;
+    }
+
+    @Override
+    public SpaceReportResponse getSpaceReport(SpaceReportRequest request) {
+        if (request == null || request.getSpaces() == null || request.getSpaces().isEmpty()) {
+            return createEmptySpaceReport();
+        }
+
+        // 解析时间
+        LocalDateTime startTime = parseDateTime(request.getStartTime());
+        LocalDateTime endTime = parseDateTime(request.getEndTime());
+        if (startTime == null || endTime == null) {
+            return createEmptySpaceReport();
+        }
+
+        // 校验时间参数
+        validateTimeParams(startTime, endTime, request.getDateType());
+
+        // 生成列定义
+        List<EnergyReportResponse.ColumnItem> columnList = generateSpaceReportColumns(request.getDateType(), startTime, endTime);
+
+        // 生成数据列表
+        List<Map<String, Object>> valueList = generateSpaceReportData(request, startTime, endTime);
+
+        // 计算总计
+        Number total = calculateSpaceReportTotal(valueList);
+
+        SpaceReportResponse response = new SpaceReportResponse();
+        response.setColumnList(columnList);
+        response.setValueList(valueList);
+        response.setTotal(total);
+
+        return response;
+    }
+
+    // ==================== 能源报表私有方法 ====================
+
+    /**
+     * 生成能源报表列定义
+     */
+    private List<EnergyReportResponse.ColumnItem> generateEnergyReportColumns(String timeType, LocalDateTime startTime, LocalDateTime endTime) {
+        List<EnergyReportResponse.ColumnItem> columns = new ArrayList<>();
+
+        // 固定列
+        columns.add(createColumn("设备名称", "deviceName", true));
+        columns.add(createColumn("通讯地址", "commAddress", true));
+        columns.add(createColumn("功能点", "identifier", true));
+        columns.add(createColumn("合计", "total", true));
+
+        // 动态时间列
+        List<String> timeLabels = generateTimeLabels(timeType, startTime, endTime);
+        for (String label : timeLabels) {
+            columns.add(createColumn(label, "_" + label.replace("时", "").replace("日", "").replace("月", ""), false));
+        }
+
+        return columns;
+    }
+
+    /**
+     * 生成能源报表数据
+     */
+    private List<EnergyReportResponse.ValueItem> generateEnergyReportData(EnergyReportRequest request, LocalDateTime startTime, LocalDateTime endTime) {
+        List<EnergyReportResponse.ValueItem> valueList = new ArrayList<>();
+
+        for (EnergyReportRequest.DeviceItem device : request.getDeviceList()) {
+            if (device == null || StringUtils.isEmpty(device.getId())) {
+                continue;
+            }
+
+            // 查询该设备的能耗数据
+            Map<String, String> timeData = queryDeviceEnergyData(device.getId(), startTime, endTime, request.getTimeType());
+
+            // 计算合计
+            String total = calculateTotal(timeData);
+
+            EnergyReportResponse.ValueItem item = new EnergyReportResponse.ValueItem();
+            item.setDeviceId(device.getId());
+            item.setDeviceName(device.getName());
+            item.setCommAddress(device.getCommAddress());
+            item.setIdentifier(request.getFuncList() != null && !request.getFuncList().isEmpty()
+                    ? request.getFuncList().get(0).getIdentifierName() : "-");
+            item.setTotal(total);
+            item.setTimeData(timeData);
+
+            valueList.add(item);
+        }
+
+        return valueList;
+    }
+
+    /**
+     * 查询设备能耗数据(模拟实现,实际应从TDengine或能耗表查询)
+     */
+    private Map<String, String> queryDeviceEnergyData(String deviceId, LocalDateTime startTime, LocalDateTime endTime, String timeType) {
+        Map<String, String> data = new LinkedHashMap<>();
+
+        // TODO: 实际应从数据库查询真实数据
+        // 这里使用模拟数据
+        List<String> timeLabels = generateTimeLabels(timeType, startTime, endTime);
+        for (String label : timeLabels) {
+            String key = "_" + label.replace("时", "").replace("日", "").replace("月", "");
+            data.put(key, "-"); // 模拟无数据
+        }
+
+        return data;
+    }
+
+    /**
+     * 计算合计值
+     */
+    private String calculateTotal(Map<String, String> timeData) {
+        if (timeData == null || timeData.isEmpty()) {
+            return "-";
+        }
+
+        BigDecimal sum = BigDecimal.ZERO;
+        boolean hasData = false;
+        for (String value : timeData.values()) {
+            if (!"-".equals(value)) {
+                try {
+                    sum = sum.add(new BigDecimal(value));
+                    hasData = true;
+                } catch (NumberFormatException e) {
+                    // 忽略无效数据
+                }
+            }
+        }
+
+        return hasData ? sum.toString() : "-";
+    }
+
+    // ==================== 分项报表私有方法 ====================
+
+    /**
+     * 生成分项报表标题列
+     */
+    private List<ItemReportResponse.TitleItem> generateItemReportTitles(String dateType, LocalDateTime startTime, LocalDateTime endTime) {
+        List<ItemReportResponse.TitleItem> titles = new ArrayList<>();
+
+        // 固定列
+        titles.add(createTitleItem("name", true, "分项名称", null));
+        titles.add(createTitleItem("total", true, "合计", null));
+
+        // 动态时间列
+        List<String> timeLabels = generateTimeLabels(dateType, startTime, endTime);
+        int index = 1;
+        for (String label : timeLabels) {
+            titles.add(createTitleItem("_" + index, false, label, index));
+            index++;
+        }
+
+        return titles;
+    }
+
+    /**
+     * 生成分项报表数据
+     */
+    private List<Map<String, Object>> generateItemReportData(ItemReportRequest request, LocalDateTime startTime, LocalDateTime endTime) {
+        List<Map<String, Object>> dataList = new ArrayList<>();
+
+        for (ItemReportRequest.ItemCodeItem itemCode : request.getItemCodes()) {
+            if (itemCode == null || StringUtils.isEmpty(itemCode.getCode())) {
+                continue;
+            }
+
+            Map<String, Object> row = new LinkedHashMap<>();
+            row.put("name", itemCode.getName());
+
+            // 查询分项能耗数据(模拟)
+            Map<String, Number> timeData = queryItemEnergyData(itemCode.getCode(), request.getSpaceId(),
+                    startTime, endTime, request.getDateType());
+
+            // 计算合计
+            Number total = calculateItemTotal(timeData);
+            row.put("total", total);
+
+            // 添加时间列数据
+            int index = 1;
+            for (Number value : timeData.values()) {
+                row.put("_" + index, value);
+                index++;
+            }
+
+            dataList.add(row);
+        }
+
+        return dataList;
+    }
+
+    /**
+     * 查询分项能耗数据(模拟实现)
+     */
+    private Map<String, Number> queryItemEnergyData(String itemCode, Long spaceId,
+                                                    LocalDateTime startTime, LocalDateTime endTime, String dateType) {
+        Map<String, Number> data = new LinkedHashMap<>();
+
+        // TODO: 实际应从数据库查询真实数据
+        List<String> timeLabels = generateTimeLabels(dateType, startTime, endTime);
+        for (String label : timeLabels) {
+            data.put(label, 0); // 模拟数据为0
+        }
+
+        return data;
+    }
+
+    /**
+     * 计算分项合计
+     */
+    private Number calculateItemTotal(Map<String, Number> timeData) {
+        if (timeData == null || timeData.isEmpty()) {
+            return 0;
+        }
+
+        double sum = 0;
+        for (Number value : timeData.values()) {
+            sum += value.doubleValue();
+        }
+        return sum;
+    }
+
+    // ==================== 区域报表私有方法 ====================
+
+    /**
+     * 生成区域报表列定义
+     */
+    private List<EnergyReportResponse.ColumnItem> generateSpaceReportColumns(String dateType, LocalDateTime startTime, LocalDateTime endTime) {
+        List<EnergyReportResponse.ColumnItem> columns = new ArrayList<>();
+
+        // 固定列
+        columns.add(createColumn("区域名称", "spaceName", true));
+        columns.add(createColumn("分项名称", "itemName", true));
+        columns.add(createColumn("合计", "total", true));
+
+        // 动态时间列
+        List<String> timeLabels = generateTimeLabels(dateType, startTime, endTime);
+        for (String label : timeLabels) {
+            columns.add(createColumn(label, "_" + label.replace("月", ""), false));
+        }
+
+        return columns;
+    }
+
+    /**
+     * 生成区域报表数据
+     */
+    private List<Map<String, Object>> generateSpaceReportData(SpaceReportRequest request, LocalDateTime startTime, LocalDateTime endTime) {
+        List<Map<String, Object>> valueList = new ArrayList<>();
+
+        for (SpaceReportRequest.SpaceItem space : request.getSpaces()) {
+            if (space == null || space.getId() == null) {
+                continue;
+            }
+
+            for (SpaceReportRequest.ItemCodeItem itemCode : request.getItemCodes()) {
+                if (itemCode == null || StringUtils.isEmpty(itemCode.getCode())) {
+                    continue;
+                }
+
+                Map<String, Object> row = new LinkedHashMap<>();
+                row.put("spaceName", space.getName());
+                row.put("itemName", itemCode.getName());
+
+                // 查询区域分项能耗数据(模拟)
+                Map<String, Number> timeData = querySpaceItemEnergyData(space.getId(), itemCode.getCode(),
+                        startTime, endTime, request.getDateType());
+
+                // 计算合计
+                Number total = calculateItemTotal(timeData);
+                row.put("total", total);
+
+                // 添加时间列数据
+                int index = 1;
+                for (Number value : timeData.values()) {
+                    row.put("_" + index, value);
+                    index++;
+                }
+
+                valueList.add(row);
+            }
+        }
+
+        return valueList;
+    }
+
+    /**
+     * 查询区域分项能耗数据(模拟实现)
+     */
+    private Map<String, Number> querySpaceItemEnergyData(Long spaceId, String itemCode,
+                                                         LocalDateTime startTime, LocalDateTime endTime, String dateType) {
+        Map<String, Number> data = new LinkedHashMap<>();
+
+        // TODO: 实际应从数据库查询真实数据
+        List<String> timeLabels = generateTimeLabels(dateType, startTime, endTime);
+        for (String label : timeLabels) {
+            data.put(label, 0); // 模拟数据为0
+        }
+
+        return data;
+    }
+
+    /**
+     * 计算区域报表总计
+     */
+    private Number calculateSpaceReportTotal(List<Map<String, Object>> valueList) {
+        if (valueList == null || valueList.isEmpty()) {
+            return 0;
+        }
+
+        double sum = 0;
+        for (Map<String, Object> row : valueList) {
+            Object total = row.get("total");
+            if (total instanceof Number) {
+                sum += ((Number) total).doubleValue();
+            }
+        }
+        return sum;
+    }
+
+    // ==================== 通用工具方法 ====================
+
+    /**
+     * 校验时间参数
+     * 1. 结束时间不得早于开始时间
+     * 2. 按日查询:起止时间必须是同一天
+     * 3. 按月查询:起止时间必须是同一月
+     * 4. 按年查询:起止时间必须是同一年
+     */
+    private void validateTimeParams(LocalDateTime startTime, LocalDateTime endTime, String timeType) {
+        // 基本校验:结束时间不得早于开始时间
+        if (endTime.isBefore(startTime)) {
+            throw new BusinessException("结束时间不得早于开始时间");
+        }
+
+        String type = timeType != null ? timeType.toLowerCase() : "date";
+
+        switch (type) {
+            case "date":
+                // 按日查询:必须是同一天
+                if (!startTime.toLocalDate().isEqual(endTime.toLocalDate())) {
+                    throw new BusinessException("按日查询时,起止时间必须是同一天");
+                }
+                break;
+            case "month":
+                // 按月查询:必须是同一月
+                if (startTime.getYear() != endTime.getYear() ||
+                        startTime.getMonthValue() != endTime.getMonthValue()) {
+                    throw new BusinessException("按月查询时,起止时间必须是同一月");
+                }
+                break;
+            case "year":
+                // 按年查询:必须是同一年
+                if (startTime.getYear() != endTime.getYear()) {
+                    throw new BusinessException("按年查询时,起止时间必须是同一年");
+                }
+                break;
+            default:
+                // 默认不校验
+                break;
+        }
+    }
+
+    /**
+     * 创建列定义
+     */
+    private EnergyReportResponse.ColumnItem createColumn(String label, String prop, Boolean fixed) {
+        EnergyReportResponse.ColumnItem column = new EnergyReportResponse.ColumnItem();
+        column.setLabel(label);
+        column.setProp(prop);
+        column.setFixed(fixed);
+        column.setChildren(null);
+        return column;
+    }
+
+    /**
+     * 创建标题项
+     */
+    private ItemReportResponse.TitleItem createTitleItem(String prop, Boolean fixed, String label, Integer value) {
+        ItemReportResponse.TitleItem item = new ItemReportResponse.TitleItem();
+        item.setProp(prop);
+        item.setFixed(fixed);
+        item.setLabel(label);
+        item.setValue(value);
+        return item;
+    }
+
+    /**
+     * 生成时间标签列表
+     * 规则:
+     * - 按日(date)查询 → 返回小时数据(根据起止时间的小时范围)
+     * - 按月(month)查询 → 返回日数据(01日-31日)
+     * - 按年(year)查询 → 返回月数据(1月-12月)
+     */
+    private List<String> generateTimeLabels(String timeType, LocalDateTime startTime, LocalDateTime endTime) {
+        List<String> labels = new ArrayList<>();
+
+        if (startTime == null || endTime == null) {
+            return labels;
+        }
+
+        String type = timeType != null ? timeType.toLowerCase() : "date";
+
+        switch (type) {
+            case "date":
+                // 按日查询:根据起止时间的小时来分段
+                int startHour = startTime.getHour();
+                int endHour = endTime.getHour();
+                for (int i = startHour; i <= endHour; i++) {
+                    labels.add(i + "时");
+                }
+                break;
+            case "month":
+                // 按月查询:返回日数据 01日, 02日, ..., 31日
+                LocalDate start = startTime.toLocalDate();
+                LocalDate end = endTime.toLocalDate();
+                int day = 1;
+                while (!start.isAfter(end)) {
+                    labels.add(String.format("%02d日", day));
+                    start = start.plusDays(1);
+                    day++;
+                }
+                break;
+            case "year":
+                // 按年查询:返回月数据 1月, 2月, ..., 12月
+                int startMonth = startTime.getMonthValue();
+                int endMonth = endTime.getMonthValue();
+                int year = startTime.getYear();
+                int endYear = endTime.getYear();
+
+                while (year < endYear || (year == endYear && startMonth <= endMonth)) {
+                    labels.add(startMonth + "月");
+                    startMonth++;
+                    if (startMonth > 12) {
+                        startMonth = 1;
+                        year++;
+                    }
+                }
+                break;
+            default:
+                // 默认按日查询,返回小时数据
+                for (int i = 0; i < 24; i++) {
+                    labels.add(i + "时");
+                }
+                break;
+        }
+
+        return labels;
+    }
+
+    /**
+     * 解析日期时间字符串
+     */
+    private LocalDateTime parseDateTime(String dateTimeStr) {
+        if (!StringUtils.hasText(dateTimeStr)) {
+            return null;
+        }
+        try {
+            return LocalDateTime.parse(dateTimeStr, DATE_TIME_FORMATTER);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    // ==================== 空响应创建方法 ====================
+
+    private EnergyReportResponse createEmptyEnergyReport() {
+        EnergyReportResponse response = new EnergyReportResponse();
+        response.setColumnList(new ArrayList<>());
+        response.setValueList(new ArrayList<>());
+        return response;
+    }
+
+    private ItemReportResponse createEmptyItemReport() {
+        ItemReportResponse response = new ItemReportResponse();
+        response.setTitleList(new ArrayList<>());
+        response.setDataList(new ArrayList<>());
+        return response;
+    }
+
+    private SpaceReportResponse createEmptySpaceReport() {
+        SpaceReportResponse response = new SpaceReportResponse();
+        response.setColumnList(new ArrayList<>());
+        response.setValueList(new ArrayList<>());
+        response.setTotal(0);
+        return response;
+    }
 }

+ 93 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/EnergyReportRequest.java

@@ -0,0 +1,93 @@
+package com.usky.ems.service.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 能源报表请求VO
+ */
+@Data
+public class EnergyReportRequest {
+
+    /**
+     * 开始时间,格式:yyyy-MM-dd HH:mm:ss
+     */
+    private String startTime;
+
+    /**
+     * 结束时间,格式:yyyy-MM-dd HH:mm:ss
+     */
+    private String endTime;
+
+    /**
+     * 能源类型:1-电,2-水,3-气
+     */
+    private Integer energyType;
+
+    /**
+     * 设备列表
+     */
+    private List<DeviceItem> deviceList;
+
+    /**
+     * 时间类型:hour-按小时,date-按日,month-按月,year-按年
+     */
+    private String timeType;
+
+    /**
+     * 功能点列表
+     */
+    private List<FuncItem> funcList;
+
+    @Data
+    public static class DeviceItem {
+        /**
+         * 通讯地址
+         */
+        private String commAddress;
+
+        /**
+         * 产品ID
+         */
+        private Long productId;
+
+        /**
+         * 设备名称
+         */
+        private String name;
+
+        /**
+         * 设备ID
+         */
+        private String id;
+    }
+
+    @Data
+    public static class FuncItem {
+        /**
+         * 产品ID列表
+         */
+        private List<Long> productIds;
+
+        /**
+         * 标识符
+         */
+        private String identifier;
+
+        /**
+         * 标识符名称
+         */
+        private String identifierName;
+
+        /**
+         * 标签
+         */
+        private String label;
+
+        /**
+         * 值
+         */
+        private String value;
+    }
+}

+ 79 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/EnergyReportResponse.java

@@ -0,0 +1,79 @@
+package com.usky.ems.service.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 能源报表响应VO
+ */
+@Data
+public class EnergyReportResponse {
+
+    /**
+     * 列定义列表
+     */
+    private List<ColumnItem> columnList;
+
+    /**
+     * 数据值列表
+     */
+    private List<ValueItem> valueList;
+
+    @Data
+    public static class ColumnItem {
+        /**
+         * 列标签
+         */
+        private String label;
+
+        /**
+         * 列属性名
+         */
+        private String prop;
+
+        /**
+         * 是否固定列
+         */
+        private Boolean fixed;
+
+        /**
+         * 子列(用于多级表头)
+         */
+        private List<ColumnItem> children;
+    }
+
+    @Data
+    public static class ValueItem {
+        /**
+         * 设备ID
+         */
+        private String deviceId;
+
+        /**
+         * 设备名称
+         */
+        private String deviceName;
+
+        /**
+         * 通讯地址
+         */
+        private String commAddress;
+
+        /**
+         * 功能点标识符
+         */
+        private String identifier;
+
+        /**
+         * 合计值
+         */
+        private String total;
+
+        /**
+         * 动态时间列数据,key为 _0, _1, _2... 或 _1, _2...31 等
+         * 使用Map存储动态列
+         */
+        private java.util.Map<String, String> timeData;
+    }
+}

+ 50 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/ItemReportRequest.java

@@ -0,0 +1,50 @@
+package com.usky.ems.service.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 分项报表请求VO
+ */
+@Data
+public class ItemReportRequest {
+
+    /**
+     * 空间ID
+     */
+    private Long spaceId;
+
+    /**
+     * 开始时间,格式:yyyy-MM-dd HH:mm:ss
+     */
+    private String startTime;
+
+    /**
+     * 结束时间,格式:yyyy-MM-dd HH:mm:ss
+     */
+    private String endTime;
+
+    /**
+     * 分项编码列表
+     */
+    private List<ItemCodeItem> itemCodes;
+
+    /**
+     * 日期类型:day-按日,month-按月,year-按年
+     */
+    private String dateType;
+
+    @Data
+    public static class ItemCodeItem {
+        /**
+         * 分项编码
+         */
+        private String code;
+
+        /**
+         * 分项名称
+         */
+        private String name;
+    }
+}

+ 46 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/ItemReportResponse.java

@@ -0,0 +1,46 @@
+package com.usky.ems.service.vo;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 分项报表响应VO
+ */
+@Data
+public class ItemReportResponse {
+
+    /**
+     * 数据列表
+     */
+    private List<Map<String, Object>> dataList;
+
+    /**
+     * 标题列定义列表
+     */
+    private List<TitleItem> titleList;
+
+    @Data
+    public static class TitleItem {
+        /**
+         * 列属性名
+         */
+        private String prop;
+
+        /**
+         * 是否固定列
+         */
+        private Boolean fixed;
+
+        /**
+         * 列标签
+         */
+        private String label;
+
+        /**
+         * 值(可选,用于序号等)
+         */
+        private Integer value;
+    }
+}

+ 63 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/SpaceReportRequest.java

@@ -0,0 +1,63 @@
+package com.usky.ems.service.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 区域报表请求VO
+ */
+@Data
+public class SpaceReportRequest {
+
+    /**
+     * 区域列表
+     */
+    private List<SpaceItem> spaces;
+
+    /**
+     * 开始时间,格式:yyyy-MM-dd HH:mm:ss
+     */
+    private String startTime;
+
+    /**
+     * 结束时间,格式:yyyy-MM-dd HH:mm:ss
+     */
+    private String endTime;
+
+    /**
+     * 分项编码列表
+     */
+    private List<ItemCodeItem> itemCodes;
+
+    /**
+     * 日期类型:month-按月,year-按年
+     */
+    private String dateType;
+
+    @Data
+    public static class SpaceItem {
+        /**
+         * 区域ID
+         */
+        private Long id;
+
+        /**
+         * 区域名称
+         */
+        private String name;
+    }
+
+    @Data
+    public static class ItemCodeItem {
+        /**
+         * 分项编码
+         */
+        private String code;
+
+        /**
+         * 分项名称
+         */
+        private String name;
+    }
+}

+ 28 - 0
service-ems/service-ems-biz/src/main/java/com/usky/ems/service/vo/SpaceReportResponse.java

@@ -0,0 +1,28 @@
+package com.usky.ems.service.vo;
+
+import lombok.Data;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 区域报表响应VO
+ */
+@Data
+public class SpaceReportResponse {
+
+    /**
+     * 列定义列表
+     */
+    private List<EnergyReportResponse.ColumnItem> columnList;
+
+    /**
+     * 数据值列表
+     */
+    private List<Map<String, Object>> valueList;
+
+    /**
+     * 合计值
+     */
+    private Number total;
+}

+ 405 - 0
service-ems/service-ems-biz/src/main/resources/InterfaceDesign.md

@@ -0,0 +1,405 @@
+**接口要求**:
+
+1.根据当前项目代码风格来编写,检查现有VO、枚举、工具类等,不要重复新建;
+2.下面三个接口目前已经存在并且有实现,先进行检查是否满足接口实现和要求,若满足则进行代码优化,不满足则重新实现;
+3.三个接口的导出功能是前端实现,后端无需实现;
+
+
+
+# 1.能源报表
+
+请求体示例:
+
+```json
+{
+    "startTime": "2026-06-09 00:00:00",
+    "endTime": "2026-06-09 15:00:00",
+    "energyType": 1,
+    "deviceList": [
+        {
+            "commAddress": "137",
+            "productId": 14,
+            "name": "阀控电表测试",
+            "id": "OYEXY5VJO9C00"
+        }
+    ],
+    "timeType": "date",
+    "funcList": [
+        {
+            "productIds": [
+                14
+            ],
+            "identifier": "11X",
+            "identifierName": "正向有功电能",
+            "label": "正向有功电能",
+            "value": "11X"
+        }
+    ]
+}
+```
+
+返回体仅参考,字段名等与实际项目不一致按项目实际情况实现。
+返回体示例:
+
+```json
+{
+    "code": "200",
+    "message": "",
+    "data": {
+        "columnList": [
+            {
+                "label": "设备名称",
+                "prop": "deviceName",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "通讯地址",
+                "prop": "commAddress",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "功能点",
+                "prop": "identifier",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "合计",
+                "prop": "total",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "0时",
+                "prop": "_0",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "1时",
+                "prop": "_1",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "2时",
+                "prop": "_2",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "3时",
+                "prop": "_3",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "4时",
+                "prop": "_4",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "5时",
+                "prop": "_5",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "6时",
+                "prop": "_6",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "7时",
+                "prop": "_7",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "8时",
+                "prop": "_8",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "9时",
+                "prop": "_9",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "10时",
+                "prop": "_10",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "11时",
+                "prop": "_11",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "12时",
+                "prop": "_12",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "13时",
+                "prop": "_13",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "14时",
+                "prop": "_14",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "15时",
+                "prop": "_15",
+                "fixed": false,
+                "children": null
+            }
+        ],
+        "valueList": [
+            {
+                "deviceId": "OYEXY5VJO9C00",
+                "deviceName": "阀控电表测试",
+                "commAddress": "137",
+                "identifier": "正向有功电能",
+                "_0": "-",
+                "_1": "-",
+                "_2": "-",
+                "_3": "-",
+                "_4": "-",
+                "_5": "-",
+                "_6": "-",
+                "_7": "-",
+                "_8": "-",
+                "_9": "-",
+                "_10": "-",
+                "_11": "-",
+                "_12": "-",
+                "_13": "-",
+                "_14": "-",
+                "_15": "-",
+                "total": "-"
+            }
+        ]
+    }
+}
+```
+
+
+
+# 2.分项报表
+
+请求体示例:
+
+```json
+{
+    "spaceId": 30,
+    "startTime": "2026-06-01 00:00:00",
+    "endTime": "2026-06-09 00:00:00",
+    "itemCodes": [
+        {
+            "code": "10100000",
+            "name": "照明插座系统用电"
+        }
+    ],
+    "dateType": "month"
+}
+```
+
+返回体仅参考,字段名等与实际项目不一致按项目实际情况实现。
+
+返回体示例:
+
+```json
+{
+    "code": "200",
+    "message": "",
+    "data": {
+        "dataList": [
+            {
+                "_1": 0,
+                "total": 0,
+                "_2": 0,
+                "_3": 0,
+                "_4": 0,
+                "_5": 0,
+                "_6": 0,
+                "_7": 0,
+                "name": "照明插座系统用电",
+                "_8": 0,
+                "_9": 0
+            }
+        ],
+        "titleList": [
+            {
+                "prop": "name",
+                "fixed": true,
+                "label": "分项名称"
+            },
+            {
+                "prop": "total",
+                "fixed": true,
+                "label": "合计"
+            },
+            {
+                "prop": "_1",
+                "label": "01日",
+                "value": 1
+            },
+            {
+                "prop": "_2",
+                "label": "02日",
+                "value": 2
+            },
+            {
+                "prop": "_3",
+                "label": "03日",
+                "value": 3
+            },
+            {
+                "prop": "_4",
+                "label": "04日",
+                "value": 4
+            },
+            {
+                "prop": "_5",
+                "label": "05日",
+                "value": 5
+            },
+            {
+                "prop": "_6",
+                "label": "06日",
+                "value": 6
+            },
+            {
+                "prop": "_7",
+                "label": "07日",
+                "value": 7
+            },
+            {
+                "prop": "_8",
+                "label": "08日",
+                "value": 8
+            },
+            {
+                "prop": "_9",
+                "label": "09日",
+                "value": 9
+            }
+        ]
+    }
+}
+```
+
+
+
+# 3.区域报表
+
+请求体示例:
+
+```json
+{
+    "spaces": [
+        {
+            "id": 30,
+            "name": "监控区域"
+        }
+    ],
+    "startTime": "2026-01-01 00:00:00",
+    "endTime": "2026-06-01 00:00:00",
+    "itemCodes": [
+        {
+            "code": "70100000",
+            "name": "太阳能热水系统"
+        },
+        {
+            "code": "70101000",
+            "name": "太阳能热水系统累计产热量"
+        }
+    ],
+    "dateType": "year"
+}
+```
+
+
+返回体仅参考,字段名等与实际项目不一致按项目实际情况实现。
+返回体示例:
+
+```json
+{
+    "code": "200",
+    "message": "",
+    "data": {
+        "columnList": [
+            {
+                "label": "区域名称",
+                "prop": "spaceName",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "分项名称",
+                "prop": "itemName",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "合计",
+                "prop": "total",
+                "fixed": true,
+                "children": null
+            },
+            {
+                "label": "1月",
+                "prop": "_1",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "2月",
+                "prop": "_2",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "3月",
+                "prop": "_3",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "4月",
+                "prop": "_4",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "5月",
+                "prop": "_5",
+                "fixed": false,
+                "children": null
+            },
+            {
+                "label": "6月",
+                "prop": "_6",
+                "fixed": false,
+                "children": null
+            }
+        ],
+        "valueList": [],
+        "total": 0
+    }
+}
+```