|
@@ -13,52 +13,29 @@ import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.date.StopWatch;
|
|
|
import cn.hutool.core.lang.Assert;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
-import com.alibaba.excel.EasyExcel;
|
|
|
-import com.alibaba.excel.support.ExcelTypeEnum;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.github.jfcloud.influxdb.flux.AggregationWindow;
|
|
|
import com.google.common.collect.Lists;
|
|
|
-import com.itextpdf.awt.DefaultFontMapper;
|
|
|
import com.itextpdf.io.image.ImageData;
|
|
|
import com.itextpdf.io.image.ImageDataFactory;
|
|
|
+import com.itextpdf.layout.element.Image;
|
|
|
import com.itextpdf.kernel.colors.ColorConstants;
|
|
|
import com.itextpdf.kernel.font.PdfFont;
|
|
|
import com.itextpdf.kernel.font.PdfFontFactory;
|
|
|
import com.itextpdf.kernel.geom.PageSize;
|
|
|
-import com.itextpdf.kernel.geom.Rectangle;
|
|
|
import com.itextpdf.kernel.pdf.PdfDocument;
|
|
|
import com.itextpdf.kernel.pdf.PdfWriter;
|
|
|
-import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
|
|
|
-import com.itextpdf.layout.Canvas;
|
|
|
import com.itextpdf.layout.Document;
|
|
|
import com.itextpdf.layout.element.*;
|
|
|
import com.itextpdf.layout.properties.HorizontalAlignment;
|
|
|
import com.itextpdf.layout.properties.TextAlignment;
|
|
|
-import com.itextpdf.text.BadElementException;
|
|
|
-import com.itextpdf.text.pdf.PdfContentByte;
|
|
|
-import com.itextpdf.text.pdf.PdfTemplate;
|
|
|
+import com.itextpdf.layout.properties.UnitValue;
|
|
|
import jakarta.servlet.http.HttpServletResponse;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
-import org.jfree.chart.ChartFactory;
|
|
|
-import org.jfree.chart.JFreeChart;
|
|
|
-import org.jfree.chart.StandardChartTheme;
|
|
|
-import org.jfree.chart.axis.CategoryAxis;
|
|
|
-import org.jfree.chart.axis.CategoryLabelPositions;
|
|
|
-import org.jfree.chart.axis.NumberAxis;
|
|
|
-import org.jfree.chart.axis.ValueAxis;
|
|
|
-import org.jfree.chart.plot.CategoryPlot;
|
|
|
-import org.jfree.chart.plot.PlotOrientation;
|
|
|
-import org.jfree.chart.plot.XYPlot;
|
|
|
-import org.jfree.chart.renderer.category.LineAndShapeRenderer;
|
|
|
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
|
|
|
-import org.jfree.data.category.CategoryDataset;
|
|
|
-import org.jfree.data.category.DefaultCategoryDataset;
|
|
|
-import org.jfree.data.xy.XYSeries;
|
|
|
-import org.jfree.data.xy.XYDataset;
|
|
|
-import org.jfree.data.xy.XYSeriesCollection;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.web.multipart.MultipartFile;
|
|
|
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
|
|
|
import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
|
|
|
import vip.xiaonuo.coldchain.core.service.JfcloudSensorDataService;
|
|
@@ -75,8 +52,6 @@ import vip.xiaonuo.coldchain.modular.monitortargetregion.service.MonitorTargetRe
|
|
|
import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
|
|
|
import vip.xiaonuo.common.exception.CommonException;
|
|
|
|
|
|
-import java.awt.*;
|
|
|
-import java.awt.image.BufferedImage;
|
|
|
import java.io.*;
|
|
|
import java.net.URLEncoder;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
@@ -557,121 +532,6 @@ public class AppDeviceService {
|
|
|
SensorEchartDataResult sensorEchartDataResult = queryDataByDeviceIdAndRoads(appDeviceQueryParams);
|
|
|
stopWatch.stop();
|
|
|
|
|
|
- stopWatch.start("导出数据");
|
|
|
- List<ExportParam> exportParamList = new ArrayList<>();
|
|
|
- ExportParam exportParam = new ExportParam();
|
|
|
- exportParam.setRegionName(monitorTargetRegion.getName());
|
|
|
- exportParam.setDeviceCode(trendParam.getSensorCode());
|
|
|
- exportParam.setSensorRoad(trendParam.getRoads());
|
|
|
- String sensorType = monitorTargetRegion.getSensorType().toUpperCase();
|
|
|
- for (char type : sensorType.toCharArray()) {
|
|
|
- LinkedHashSet<String> x;
|
|
|
- List<Float> y;
|
|
|
- if (type == 'W') {
|
|
|
- exportParam.setDataType("温度");
|
|
|
- x = sensorEchartDataResult.getTemperature().getX();
|
|
|
- y = sensorEchartDataResult.getTemperature().getY();
|
|
|
- } else if (type == 'S') {
|
|
|
- exportParam.setDataType("湿度");
|
|
|
- x = sensorEchartDataResult.getHumidity().getX();
|
|
|
- y = sensorEchartDataResult.getHumidity().getY();
|
|
|
- } else if (type == 'C') {
|
|
|
- exportParam.setDataType("二氧化碳浓度");
|
|
|
- x = sensorEchartDataResult.getCo2().getX();
|
|
|
- y = sensorEchartDataResult.getCo2().getY();
|
|
|
- } else {
|
|
|
- log.warn("未知的传感器类型:{}", type);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- int i = 0;
|
|
|
- for (String s : x) {
|
|
|
- ExportParam exportParamOut = BeanUtil.copyProperties(exportParam, ExportParam.class);
|
|
|
- exportParamOut.setTime(s);
|
|
|
- exportParamOut.setData(y.get(i));
|
|
|
- i++;
|
|
|
- exportParamList.add(exportParamOut);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- String fileName = "传感器数据.pdf";
|
|
|
- response.setContentType("application/pdf");
|
|
|
- response.setCharacterEncoding("utf-8");
|
|
|
- response.setHeader("Content-disposition", "attachment;filename*=utf-8''" +
|
|
|
- URLEncoder.encode(fileName, StandardCharsets.UTF_8));
|
|
|
-
|
|
|
- try (OutputStream outputStream = response.getOutputStream()) {
|
|
|
- // 1. 初始化PDF文档
|
|
|
- PdfWriter writer = new PdfWriter(outputStream);
|
|
|
- PdfDocument pdfDoc = new PdfDocument(writer);
|
|
|
- Document document = new Document(pdfDoc, PageSize.A4.rotate());
|
|
|
-
|
|
|
- // 2. 创建表格(根据字段数量设置列数)
|
|
|
- Table table = new Table(ExportParam.class.getDeclaredFields ().length); // 时间、区域、设备编码、传感器路数、数据类型、数据值
|
|
|
- table.useAllAvailableWidth();
|
|
|
-
|
|
|
- // 3. 添加表格标题
|
|
|
- Paragraph title = new Paragraph("传感器数据报表")
|
|
|
- .setTextAlignment(TextAlignment.CENTER)
|
|
|
- .setFontSize(16);
|
|
|
- document.add(title);
|
|
|
-
|
|
|
- // 4. 添加表头
|
|
|
- String[] headers = {"时间", "区域名称", "设备编码", "传感器路数", "数据类型", "数据值"};
|
|
|
- for (String header : headers) {
|
|
|
- table.addHeaderCell(new Cell().add(new Paragraph(header))
|
|
|
- .setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
|
|
|
- .setBackgroundColor(ColorConstants.LIGHT_GRAY)
|
|
|
- .setTextAlignment(TextAlignment.CENTER));
|
|
|
- }
|
|
|
-
|
|
|
- // 5. 填充表格数据
|
|
|
- for (ExportParam param : exportParamList) {
|
|
|
- addPdfTableRow(table, param.getTime());
|
|
|
- addPdfTableRow(table, param.getRegionName());
|
|
|
- addPdfTableRow(table, param.getDeviceCode());
|
|
|
- addPdfTableRow(table, String.valueOf(param.getSensorRoad()));
|
|
|
- addPdfTableRow(table, param.getDataType());
|
|
|
- addPdfTableRow(table, String.valueOf(param.getData()));
|
|
|
- }
|
|
|
-
|
|
|
- // 6. 将表格加入文档
|
|
|
- document.add(table);
|
|
|
-
|
|
|
- // 7. 关闭资源
|
|
|
- document.close();
|
|
|
- log.info("PDF生成完成");
|
|
|
-
|
|
|
- } catch (IOException e) {
|
|
|
- throw new RuntimeException("PDF生成失败", e);
|
|
|
- } finally {
|
|
|
- stopWatch.stop();
|
|
|
- log.info("PDF导出耗时:{}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 辅助方法:添加表格单元格
|
|
|
- private void addPdfTableRow(Table table, String content) throws IOException {
|
|
|
- table.addCell(new Cell().add(new Paragraph(content))
|
|
|
- .setFont(PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"))
|
|
|
- .setTextAlignment(TextAlignment.CENTER));
|
|
|
- }*/
|
|
|
- public void export(HttpServletResponse response, AppTrendParam trendParam) {
|
|
|
- StopWatch stopWatch = new StopWatch("传感器数据导出");
|
|
|
-
|
|
|
- stopWatch.start("查询设备信息");
|
|
|
- MonitorTargetRegion monitorTargetRegion = monitorTargetRegionService.findOneByDeviceCodeAndSensorNo(trendParam.getSensorCode(), trendParam.getRoads());
|
|
|
- stopWatch.stop();
|
|
|
- if (Objects.isNull(monitorTargetRegion)) {
|
|
|
- throw new CommonException("未找到设备编号 [{}] 和传感器编号 [{}] 对应的监控目标区域。", trendParam.getSensorCode(), trendParam.getRoads());
|
|
|
- }
|
|
|
-
|
|
|
- stopWatch.start("查询传感器数据");
|
|
|
- AppDeviceQueryParams appDeviceQueryParams = BeanUtil.copyProperties(trendParam, AppDeviceQueryParams.class);
|
|
|
- appDeviceQueryParams.setSensorRoute(trendParam.getRoads());
|
|
|
- SensorEchartDataResult sensorEchartDataResult = queryDataByDeviceIdAndRoads(appDeviceQueryParams);
|
|
|
- stopWatch.stop();
|
|
|
-
|
|
|
// 计算统计信息
|
|
|
stopWatch.start("计算统计信息");
|
|
|
List<Float> temperatureData = sensorEchartDataResult.getTemperature().getY();
|
|
@@ -876,6 +736,203 @@ public class AppDeviceService {
|
|
|
});
|
|
|
document.add(dataTable);
|
|
|
|
|
|
+ document.close();
|
|
|
+ } catch (Exception e) {
|
|
|
+ throw new RuntimeException("PDF生成失败", e);
|
|
|
+ } finally {
|
|
|
+ stopWatch.stop();
|
|
|
+ log.info("PDF导出耗时:{}", stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
|
|
|
+ }
|
|
|
+ }*/
|
|
|
+
|
|
|
+ public void export(HttpServletResponse response, AppTrendParam trendParam, MultipartFile file) {
|
|
|
+ StopWatch stopWatch = new StopWatch("传感器数据导出");
|
|
|
+
|
|
|
+ stopWatch.start("查询设备信息");
|
|
|
+ MonitorTargetRegion monitorTargetRegion = monitorTargetRegionService.findOneByDeviceCodeAndSensorNo(trendParam.getSensorCode(), trendParam.getRoads());
|
|
|
+ stopWatch.stop();
|
|
|
+ if (Objects.isNull(monitorTargetRegion)) {
|
|
|
+ throw new CommonException("未找到设备编号 [{}] 和传感器编号 [{}] 对应的监控目标区域。", trendParam.getSensorCode(), trendParam.getRoads());
|
|
|
+ }
|
|
|
+
|
|
|
+ stopWatch.start("查询传感器数据");
|
|
|
+ AppDeviceQueryParams appDeviceQueryParams = BeanUtil.copyProperties(trendParam, AppDeviceQueryParams.class);
|
|
|
+ appDeviceQueryParams.setSensorRoute(trendParam.getRoads());
|
|
|
+ SensorEchartDataResult sensorEchartDataResult = queryDataByDeviceIdAndRoads(appDeviceQueryParams);
|
|
|
+ stopWatch.stop();
|
|
|
+
|
|
|
+ // 计算统计信息
|
|
|
+ stopWatch.start("计算统计信息");
|
|
|
+ List<Float> temperatureData = sensorEchartDataResult.getTemperature().getY();
|
|
|
+ float maxTemp = Collections.max(temperatureData);
|
|
|
+ float minTemp = Collections.min(temperatureData);
|
|
|
+ float avgTemp = (float) temperatureData.stream().mapToDouble(f -> f).average().orElse(0.0);
|
|
|
+ stopWatch.stop();
|
|
|
+
|
|
|
+ stopWatch.start("导出数据");
|
|
|
+ List<ExportParam> exportParamList = new ArrayList<>();
|
|
|
+ ExportParam exportParam = new ExportParam();
|
|
|
+ exportParam.setRegionName(monitorTargetRegion.getName());
|
|
|
+ exportParam.setDeviceCode(trendParam.getSensorCode());
|
|
|
+ exportParam.setSensorRoad(trendParam.getRoads());
|
|
|
+ String sensorType = monitorTargetRegion.getSensorType().toUpperCase();
|
|
|
+
|
|
|
+ // 仅处理温度数据('W'类型)
|
|
|
+ if (sensorType.contains("W")) {
|
|
|
+ exportParam.setDataType("温度");
|
|
|
+ LinkedHashSet<String> x = sensorEchartDataResult.getTemperature().getX();
|
|
|
+ List<Float> y = sensorEchartDataResult.getTemperature().getY();
|
|
|
+ int i = 0;
|
|
|
+ for (String time : x) {
|
|
|
+ ExportParam exportParamOut = BeanUtil.copyProperties(exportParam, ExportParam.class);
|
|
|
+ exportParamOut.setTime(time);
|
|
|
+ exportParamOut.setData(y.get(i));
|
|
|
+ exportParamList.add(exportParamOut);
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ String fileName = "传感器数据报告.pdf";
|
|
|
+ response.setContentType("application/pdf");
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
+ response.setHeader("Content-disposition", "attachment;filename*=utf-8''" +
|
|
|
+ URLEncoder.encode(fileName, StandardCharsets.UTF_8));
|
|
|
+
|
|
|
+ try (OutputStream outputStream = response.getOutputStream()) {
|
|
|
+ PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
|
|
|
+ PdfWriter writer = new PdfWriter(outputStream);
|
|
|
+ PdfDocument pdfDoc = new PdfDocument(writer);
|
|
|
+ Document document = new Document(pdfDoc, PageSize.A4);
|
|
|
+ document.setMargins(15, 20, 10, 20);
|
|
|
+
|
|
|
+ // 报告标题
|
|
|
+ Paragraph title = new Paragraph("传感器数据报告")
|
|
|
+ .setFont(chineseFont)
|
|
|
+ .setTextAlignment(TextAlignment.CENTER)
|
|
|
+ .setFontSize(20)
|
|
|
+ .setBold()
|
|
|
+ .setMarginBottom(10);
|
|
|
+ document.add(title);
|
|
|
+
|
|
|
+ // 报告下载时间
|
|
|
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
|
|
|
+ Paragraph downloadTime = new Paragraph("报告下载时间: " + sdf.format(new Date()))
|
|
|
+ .setFont(chineseFont)
|
|
|
+ .setFontSize(10)
|
|
|
+ .setTextAlignment(TextAlignment.LEFT);
|
|
|
+ document.add(downloadTime);
|
|
|
+
|
|
|
+ Paragraph deviceInfo = new Paragraph("设备信息")
|
|
|
+ .setFont(chineseFont)
|
|
|
+ .setTextAlignment(TextAlignment.CENTER)
|
|
|
+ .setFontSize(15)
|
|
|
+ .setBold()
|
|
|
+ .setMarginBottom(2);
|
|
|
+ document.add(deviceInfo);
|
|
|
+
|
|
|
+ float[] columnWidths = {2, 4, 2, 3};
|
|
|
+
|
|
|
+ // 设备信息表格
|
|
|
+ Table deviceTable = new Table(UnitValue.createPercentArray(columnWidths))
|
|
|
+ .useAllAvailableWidth()
|
|
|
+ .setHorizontalAlignment(HorizontalAlignment.CENTER);;
|
|
|
+ addDeviceTableRow(deviceTable, "设备名称:", monitorTargetRegion.getName().split("-")[0], "温度上限:", monitorTargetRegion.getTemperatureUp() + "°C");
|
|
|
+ addDeviceTableRow(deviceTable, "点位名称:", monitorTargetRegion.getName(), "温度下限:", monitorTargetRegion.getTemperatureDown() + "");
|
|
|
+ addDeviceTableRow(deviceTable, "冷链设备编号:", trendParam.getSensorCode(), "传感器路数:", trendParam.getRoads() + "路");
|
|
|
+ deviceTable.setMarginBottom(10);
|
|
|
+ document.add(deviceTable);
|
|
|
+
|
|
|
+ Paragraph data = new Paragraph("记录信息")
|
|
|
+ .setFont(chineseFont)
|
|
|
+ .setTextAlignment(TextAlignment.CENTER)
|
|
|
+ .setFontSize(15)
|
|
|
+ .setBold()
|
|
|
+ .setMarginBottom(2);
|
|
|
+ document.add(data);
|
|
|
+
|
|
|
+ // 记录信息表格
|
|
|
+ Table recordTable = new Table(UnitValue.createPercentArray(columnWidths))
|
|
|
+ .useAllAvailableWidth()
|
|
|
+ .setHorizontalAlignment(HorizontalAlignment.CENTER);
|
|
|
+ addRecordTableRow(recordTable, "开始时间:", trendParam.getStartTime(), "最高温度:", String.format("%.1f°C", maxTemp));
|
|
|
+ addRecordTableRow(recordTable, "结束时间:", trendParam.getEndTime(), "最低温度:", String.format("%.1f°C", minTemp));
|
|
|
+ addRecordTableRow(recordTable, "", "", "平均温度:", String.format("%.1f°C", avgTemp));
|
|
|
+ recordTable.setMarginBottom(10);
|
|
|
+ document.add(recordTable);
|
|
|
+
|
|
|
+ if (!file.isEmpty()) {
|
|
|
+ Paragraph curve = new Paragraph("温度曲线")
|
|
|
+ .setFont(chineseFont)
|
|
|
+ .setTextAlignment(TextAlignment.CENTER)
|
|
|
+ .setFontSize(15)
|
|
|
+ .setBold();
|
|
|
+ document.add(curve);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取图片字节数据
|
|
|
+ byte[] imageBytes = file.getBytes();
|
|
|
+
|
|
|
+ ImageData imageData = ImageDataFactory.create(imageBytes);
|
|
|
+ Image image = new Image(imageData);
|
|
|
+
|
|
|
+ float pageWidth = PageSize.A4.getWidth();
|
|
|
+ float scaledWidth = pageWidth * 0.8f;
|
|
|
+
|
|
|
+ image.scaleToFit(scaledWidth, image.getImageHeight());
|
|
|
+ image.setHorizontalAlignment(HorizontalAlignment.CENTER);
|
|
|
+ document.add(image);
|
|
|
+
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new RuntimeException("图片处理失败: " + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 温度数据表格
|
|
|
+ Paragraph dataTitle = new Paragraph("温度数据")
|
|
|
+ .setFont(chineseFont)
|
|
|
+ .setTextAlignment(TextAlignment.CENTER)
|
|
|
+ .setFontSize(15)
|
|
|
+ .setBold()
|
|
|
+ .setMarginBottom(2);
|
|
|
+ document.add(dataTitle);
|
|
|
+
|
|
|
+ Table dataTable = new Table(new float[]{2,1,2,1,2,1,2,1}).useAllAvailableWidth();
|
|
|
+ for (int i = 0; i < 4; i++) {
|
|
|
+ dataTable.addHeaderCell(createCell("时间", true));
|
|
|
+ dataTable.addHeaderCell(createCell("°C", true));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 数据分组逻辑(每组4条记录)
|
|
|
+ List<List<ExportParam>> groups = new ArrayList<>();
|
|
|
+ List<ExportParam> currentGroup = new ArrayList<>();
|
|
|
+ for (ExportParam param : exportParamList) {
|
|
|
+ currentGroup.add(param);
|
|
|
+ if (currentGroup.size() == 4) { // 每组4条记录(每行显示4个时间+温度)
|
|
|
+ groups.add(currentGroup);
|
|
|
+ currentGroup = new ArrayList<>();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 处理剩余数据
|
|
|
+ if (!currentGroup.isEmpty()) {
|
|
|
+ groups.add(currentGroup);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 填充表格数据
|
|
|
+ for (List<ExportParam> group : groups) {
|
|
|
+ // 添加每组数据
|
|
|
+ for (ExportParam param : group) {
|
|
|
+ dataTable.addCell(createCell(param.getTime(), false));
|
|
|
+ dataTable.addCell(createCell(String.format("%.1f", param.getData()), false));
|
|
|
+ }
|
|
|
+ // 补全空单元格(每组不足4条时)
|
|
|
+ int missing = 4 - group.size();
|
|
|
+ for (int i = 0; i < missing; i++) {
|
|
|
+ dataTable.addCell(createCell("", false));
|
|
|
+ dataTable.addCell(createCell("", false));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ document.add(dataTable);
|
|
|
+
|
|
|
document.close();
|
|
|
} catch (Exception e) {
|
|
|
throw new RuntimeException("PDF生成失败", e);
|