package com.ruoyi.energymeter.controller; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.energymeter.service.EnergyMonitorService; import com.ruoyi.energymeter.vo.EnergyCollectionVO; import com.ruoyi.energymeter.vo.EnergyRealtimeVO; import com.ruoyi.energymeter.vo.EnergyReportVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.apache.poi.ss.usermodel.BorderStyle; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.FillPatternType; import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; import java.math.BigDecimal; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.List; /** * 能耗数据采集、实时监控与统计报表接口。 * *

菜单固定在前端路由,不写数据库菜单、不配角色权限;所有登录用户可见。

*/ @RestController @Tag(name = "能耗监控与统计") @RequestMapping("/energyMeter") @RequiredArgsConstructor public class EnergyMonitorController { private final EnergyMonitorService monitorService; @GetMapping("/collection/overview") @Operation(summary = "能耗数据采集概览:三类介质接入设备、归集进度与最近批次") public AjaxResult collectionOverview() { EnergyCollectionVO vo = monitorService.collection(); return AjaxResult.success(vo); } @GetMapping("/realtime/overview") @Operation(summary = "能耗实时监控:三类介质最新用量、趋势与电表实时曲线") public AjaxResult realtimeOverview( @RequestParam(required = false) Long meterId) { EnergyRealtimeVO vo = monitorService.realtime(meterId); return AjaxResult.success(vo); } @GetMapping("/report/summary") @Operation(summary = "能耗统计分析:按日/月、按介质/设备汇总") public AjaxResult reportSummary( @RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate, @RequestParam(defaultValue = "DAY") String granularity, @RequestParam(defaultValue = "ALL") String meterType, @RequestParam(defaultValue = "MEDIUM") String dimension) { EnergyReportVO vo = monitorService.report(startDate, endDate, granularity, meterType, dimension); return AjaxResult.success(vo); } @RequestMapping(value = "/report/export", method = {RequestMethod.GET, RequestMethod.POST}) @Operation(summary = "能耗统计报表导出 Excel") public void reportExport(@RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate, @RequestParam(defaultValue = "DAY") String granularity, @RequestParam(defaultValue = "ALL") String meterType, HttpServletResponse response) throws IOException { EnergyReportVO report = monitorService.report(startDate, endDate, granularity, meterType, "MEDIUM"); String fileName = URLEncoder.encode("能耗统计报表_" + report.getStart() + "_" + report.getEnd() + ".xlsx", StandardCharsets.UTF_8).replace("+", "%20"); response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\""); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); try (Workbook workbook = new XSSFWorkbook()) { writeMediumSheet(workbook, report); writeDeviceSheet(workbook, report); workbook.write(response.getOutputStream()); } } /* ------------------------------------------------------------------ */ /* Excel */ /* ------------------------------------------------------------------ */ private void writeMediumSheet(Workbook workbook, EnergyReportVO report) { Sheet sheet = workbook.createSheet("介质汇总"); CellStyle headStyle = headStyle(workbook); CellStyle numberStyle = numberStyle(workbook); CellStyle textStyle = textStyle(workbook); String[] headers = {"统计周期", "水表用量(m³)", "电表用量(度)", "蒸汽表用量(m³)"}; Row head = sheet.createRow(0); for (int i = 0; i < headers.length; i++) { Cell cell = head.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headStyle); } int rowIndex = 1; for (EnergyReportVO.PeriodRow row : report.getRows()) { Row dataRow = sheet.createRow(rowIndex++); dataRow.createCell(0).setCellValue(row.getPeriod()); dataRow.getCell(0).setCellStyle(textStyle); writeNumber(dataRow, 1, row.getWater(), numberStyle); writeNumber(dataRow, 2, row.getElectric(), numberStyle); writeNumber(dataRow, 3, row.getGas(), numberStyle); } Row totalRow = sheet.createRow(rowIndex); Cell totalLabel = totalRow.createCell(0); totalLabel.setCellValue("合计"); totalLabel.setCellStyle(headStyle); for (EnergyReportVO.MediumTotal total : report.getTotals()) { int column = columnOf(total.getMeterType()); if (column > 0) { writeNumber(totalRow, column, total.getTotal(), numberStyle); } } sheet.setColumnWidth(0, 18 * 256); for (int i = 1; i <= 3; i++) { sheet.setColumnWidth(i, 20 * 256); } sheet.createFreezePane(0, 1); sheet.setAutoFilter(new org.apache.poi.ss.util.CellRangeAddress(0, Math.max(0, rowIndex - 1), 0, 3)); } private void writeDeviceSheet(Workbook workbook, EnergyReportVO report) { Sheet sheet = workbook.createSheet("设备明细"); CellStyle headStyle = headStyle(workbook); CellStyle numberStyle = numberStyle(workbook); CellStyle textStyle = textStyle(workbook); String[] headers = {"设备名称", "表号", "介质", "采集方式", "期间用量", "单位", "占介质比例(%)"}; Row head = sheet.createRow(0); for (int i = 0; i < headers.length; i++) { Cell cell = head.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headStyle); } int rowIndex = 1; for (EnergyReportVO.DeviceRow row : report.getDevices()) { Row dataRow = sheet.createRow(rowIndex++); createText(dataRow, 0, row.getMeterName(), textStyle); createText(dataRow, 1, row.getMeterAddress(), textStyle); createText(dataRow, 2, row.getMeterTypeName(), textStyle); createText(dataRow, 3, row.getSourceTypeName(), textStyle); writeNumber(dataRow, 4, row.getTotal(), numberStyle); createText(dataRow, 5, excelUnit(row.getUnit()), textStyle); writeNumber(dataRow, 6, row.getShare(), numberStyle); } sheet.setColumnWidth(0, 24 * 256); sheet.setColumnWidth(1, 22 * 256); for (int i = 2; i <= 6; i++) { sheet.setColumnWidth(i, 14 * 256); } sheet.createFreezePane(0, 1); sheet.setAutoFilter(new org.apache.poi.ss.util.CellRangeAddress(0, Math.max(0, rowIndex - 1), 0, 6)); } private int columnOf(String meterType) { if ("WATER".equals(meterType)) { return 1; } if ("ELECTRIC".equals(meterType)) { return 2; } if ("GAS".equals(meterType)) { return 3; } return 0; } /** 界面与报表统一用「度」,底层仍按 kWh 存储。 */ private String excelUnit(String unit) { if ("kWh".equals(unit)) { return "度"; } if ("m3".equals(unit)) { return "m³"; } return unit; } private void createText(Row row, int column, String value, CellStyle style) { Cell cell = row.createCell(column); cell.setCellValue(value == null ? "" : value); cell.setCellStyle(style); } private void writeNumber(Row row, int column, BigDecimal value, CellStyle style) { Cell cell = row.createCell(column); if (value != null) { cell.setCellValue(value.doubleValue()); } cell.setCellStyle(style); } private CellStyle headStyle(Workbook workbook) { CellStyle style = baseStyle(workbook); style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); style.setAlignment(HorizontalAlignment.CENTER); Font font = workbook.createFont(); font.setBold(true); style.setFont(font); return style; } private CellStyle textStyle(Workbook workbook) { CellStyle style = baseStyle(workbook); style.setAlignment(HorizontalAlignment.LEFT); return style; } private CellStyle numberStyle(Workbook workbook) { CellStyle style = baseStyle(workbook); style.setAlignment(HorizontalAlignment.RIGHT); style.setDataFormat(workbook.createDataFormat().getFormat("#,##0.000")); return style; } private CellStyle baseStyle(Workbook workbook) { CellStyle style = workbook.createCellStyle(); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); style.setVerticalAlignment(VerticalAlignment.CENTER); return style; } }