diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java index 0eedd3c..a8907c6 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/config/PDFGenerator.java @@ -53,16 +53,14 @@ public class PDFGenerator { private static final float CELL_PADDING = 5; private static final float[] COLUMN_WIDTHS = {LEFT_COL_WIDTH, RIGHT_COL_WIDTH}; private static final float MIN_IMAGE_HEIGHT = 50; - public static void generateInstallationPDF(DeviceInstallInfo entity, OutputStream outputStream) throws IOException { - // 首先生成PDF内容到字节数组 - ByteArrayOutputStream pdfBaos = new ByteArrayOutputStream(); + public static void generateInstallationPDFBytes(DeviceInstallInfo entity, ByteArrayOutputStream outputStream) throws IOException { try (PDDocument document = new PDDocument()) { - // 加载字体(需替换实际路径) + // 加载字体 // PDType0Font font = PDType0Font.load(document, new File("D:\\NotoSansCJK-Regular.ttf")); - //PDType0Font font = PDType0Font.load(document, new File("/ttf/simsun.ttf")); - PDType0Font font = PDType0Font.load(document, new File("/ttf/NotoSansCJK-Regular.ttf")); + PDType0Font font = PDType0Font.load(document, new File("/ttf/NotoSansCJK-Regular.ttf")); + // 初始化第一页 PDPage currentPage = new PDPage(PDRectangle.A4); document.addPage(currentPage); @@ -71,20 +69,18 @@ public class PDFGenerator { try { // 1. 绘制标题(居中) - drawCenteredText(cs, font, FONT_SIZE+10, + drawCenteredText(cs, font, FONT_SIZE + 10, "安装信息录入表", - PDRectangle.A4.getWidth()/2, currentY); + PDRectangle.A4.getWidth() / 2, currentY); currentY -= ROW_HEIGHT * 1.5f; // 2. 绘制基本信息表格 String[][] baseData = { - // {"公司名称", entity.getCorporateName()}, {"申请时间", entity.getProposerTime().toString()}, {"申请人", entity.getProposer()}, {"申请人班组", entity.getProposerTeam()}, {"小区名字", entity.getCommunityName()}, {"用户姓名", entity.getUserName()}, - // {"用户姓名", entity.getUserName()+"-" + entity.getCommunityName()+entity.getBuildingUnit()+entity.getRoomNo()}, {"电话", entity.getUserIpone()}, {"楼栋单元号", entity.getBuildingUnit()}, {"房间号", entity.getRoomNo()}, @@ -92,14 +88,11 @@ public class PDFGenerator { {"切断阀编号", entity.getShutValueNumber()}, {"燃气表号", entity.getGasMeterNumber()}, {"备注", entity.getBuildingUnit()} - }; drawTable(cs, font, TABLE_MARGIN, currentY, baseData, COLUMN_WIDTHS); currentY -= (ROW_HEIGHT * baseData.length) + 20f; -// @ApiModelProperty(value = "安装前图片") - // 创建后续页面 - 图片部分 - // 图片处理(带自动分页) - // 图片处理(带自动分页) + + // 3. 图片处理(带自动分页) List imageGroups = Arrays.asList( new String[]{entity.getDeviceInfoImage(), "设备信息图片"}, new String[]{entity.getBeforeInstallationImage(), "安装前图片"}, @@ -184,37 +177,201 @@ public class PDFGenerator { } } } - } finally { cs.close(); } - // 将PDF保存到ByteArrayOutputStream - document.save(pdfBaos); -// ByteArrayOutputStream baos = new ByteArrayOutputStream(); -// document.save(baos); -// outputStream.flush(); -// baos.writeTo(outputStream); + // 将PDF保存到输出流 + document.save(outputStream); + } + } - } - // 创建ZIP压缩包并将PDF写入输出流 + public static void generateInstallationPDF(DeviceInstallInfo entity, OutputStream outputStream) throws IOException { + ByteArrayOutputStream pdfBaos = new ByteArrayOutputStream(); + generateInstallationPDFBytes(entity, pdfBaos); + + // 创建ZIP压缩包 try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) { - // 设置最高压缩级别 zipOut.setLevel(Deflater.BEST_COMPRESSION); - // 创建ZIP条目 - ZipEntry entry = new ZipEntry(entity.getUserName()+entity.getCommunityName()+entity.getBuildingUnit()+entity.getRoomNo()+".pdf"); + ZipEntry entry = new ZipEntry(entity.getUserName() + entity.getCommunityName() + entity.getBuildingUnit() + entity.getRoomNo() + ".pdf"); zipOut.putNextEntry(entry); - // 将PDF数据写入ZIP byte[] pdfBytes = pdfBaos.toByteArray(); zipOut.write(pdfBytes, 0, pdfBytes.length); - - // 关闭当前条目 zipOut.closeEntry(); } } + // 辅助方法:生成文件名 + public static String generateFileName(DeviceInstallInfo entity) { + return entity.getUserName() + entity.getCommunityName() + + entity.getBuildingUnit() + entity.getRoomNo() + ".pdf"; + } + + +// public static void generateInstallationPDF(DeviceInstallInfo entity, OutputStream outputStream) throws IOException { +// +// // 首先生成PDF内容到字节数组 +// ByteArrayOutputStream pdfBaos = new ByteArrayOutputStream(); +// +// try (PDDocument document = new PDDocument()) { +// // 加载字体(需替换实际路径) +//// PDType0Font font = PDType0Font.load(document, new File("D:\\NotoSansCJK-Regular.ttf")); +// //PDType0Font font = PDType0Font.load(document, new File("/ttf/simsun.ttf")); +// PDType0Font font = PDType0Font.load(document, new File("/ttf/NotoSansCJK-Regular.ttf")); +// // 初始化第一页 +// PDPage currentPage = new PDPage(PDRectangle.A4); +// document.addPage(currentPage); +// PDPageContentStream cs = new PDPageContentStream(document, currentPage); +// float currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; +// +// try { +// // 1. 绘制标题(居中) +// drawCenteredText(cs, font, FONT_SIZE+10, +// "安装信息录入表", +// PDRectangle.A4.getWidth()/2, currentY); +// currentY -= ROW_HEIGHT * 1.5f; +// +// // 2. 绘制基本信息表格 +// String[][] baseData = { +// // {"公司名称", entity.getCorporateName()}, +// {"申请时间", entity.getProposerTime().toString()}, +// {"申请人", entity.getProposer()}, +// {"申请人班组", entity.getProposerTeam()}, +// {"小区名字", entity.getCommunityName()}, +// {"用户姓名", entity.getUserName()}, +// // {"用户姓名", entity.getUserName()+"-" + entity.getCommunityName()+entity.getBuildingUnit()+entity.getRoomNo()}, +// {"电话", entity.getUserIpone()}, +// {"楼栋单元号", entity.getBuildingUnit()}, +// {"房间号", entity.getRoomNo()}, +// {"报警器编号", entity.getDeviceName()}, +// {"切断阀编号", entity.getShutValueNumber()}, +// {"燃气表号", entity.getGasMeterNumber()}, +// {"备注", entity.getBuildingUnit()} +// +// }; +// drawTable(cs, font, TABLE_MARGIN, currentY, baseData, COLUMN_WIDTHS); +// currentY -= (ROW_HEIGHT * baseData.length) + 20f; +//// @ApiModelProperty(value = "安装前图片") +// // 创建后续页面 - 图片部分 +// // 图片处理(带自动分页) +// // 图片处理(带自动分页) +// List imageGroups = Arrays.asList( +// new String[]{entity.getDeviceInfoImage(), "设备信息图片"}, +// new String[]{entity.getBeforeInstallationImage(), "安装前图片"}, +// new String[]{entity.getWorkingOfTheDetectorImage(), "安装完成探测器工作图片"}, +// new String[]{entity.getSideLeakageImage(), "测漏图片"}, +// new String[]{entity.getFormSideLeakageImage(), "泡沫水测漏图片"}, +// new String[]{entity.getIgnitionPictureImage(), "点火图片"}, +// new String[]{entity.getInstallThePanoramicImage(), "安装完成全景图片"}, +// new String[]{entity.getOfGasMeterImage(), "燃气表号图片"}, +// new String[]{entity.getWorkOrderImage(), "工单图片"}, +// new String[]{entity.getPunchingImage(), "打孔图片"}, +// new String[]{entity.getFiexImage(), "安装电源线图片"}, +// new String[]{entity.getHouseNumberImage(), "门牌号图片"} +// ); +// +// for (String[] group : imageGroups) { +// String urls = group[0]; +// String title = group[1]; +// +// if (urls != null && !urls.trim().isEmpty()) { +// List validUrls = Arrays.stream(urls.split(",")) +// .map(String::trim) +// .filter(url -> !url.isEmpty() && url.startsWith("http")) +// .collect(Collectors.toList()); +// +// if (!validUrls.isEmpty()) { +// // 处理可能需要跨页的多图片情况 +// if (validUrls.size() > 2) { +// // 对于多于2张的图片,逐个或分组处理以支持跨页 +// for (int i = 0; i < validUrls.size(); i += 2) { // 每次处理最多2张图片 +// List subList = validUrls.subList(i, +// Math.min(i + 2, validUrls.size())); +// +// List wrappedTitleLines = wrapText(title,LEFT_COL_WIDTH - 2 * CELL_PADDING); +// float titleHeight = wrappedTitleLines.size() * LINE_HEIGHT; +// // 计算图片组的自适应高度 +// float imagesHeight = calculateAdjustedImagesHeight(document, subList, +// RIGHT_COL_WIDTH - 2 * CELL_PADDING, +// PDRectangle.A4.getHeight() - 2 * TABLE_MARGIN - titleHeight); +// +// float totalHeight = Math.max(imagesHeight, titleHeight); +// +// if (currentY < TABLE_MARGIN + Math.max(totalHeight, titleHeight)) { +// cs.close(); +// currentPage = new PDPage(PDRectangle.A4); +// document.addPage(currentPage); +// cs = new PDPageContentStream(document, currentPage); +// currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; +// } +// +// // 添加标识,表明这是多图片的一部分 +// String subTitle = title + " (" + (i+1) + "-" + Math.min(i+2, validUrls.size()) + "/" + validUrls.size() + ")"; +// List subWrappedTitleLines = wrapText(subTitle, LEFT_COL_WIDTH - 2 * CELL_PADDING); +// +// drawImageGroup(cs, document, font, subWrappedTitleLines, subList, currentY, +// Math.max(totalHeight, titleHeight)); +// currentY -= Math.max(totalHeight, titleHeight); +// } +// } else { +// // 原有的单/双图片处理逻辑 +// List wrappedTitleLines = wrapText(title,LEFT_COL_WIDTH - 2 * CELL_PADDING); +// float titleHeight = wrappedTitleLines.size() * LINE_HEIGHT; +// // 计算图片组的自适应高度 +// float imagesHeight = calculateAdjustedImagesHeight(document, validUrls, +// RIGHT_COL_WIDTH - 2 * CELL_PADDING, +// PDRectangle.A4.getHeight() - 2 * TABLE_MARGIN - titleHeight); +// +// float totalHeight = Math.max(imagesHeight, titleHeight); +// +// if (currentY < TABLE_MARGIN + Math.max(totalHeight, titleHeight)) { +// cs.close(); +// currentPage = new PDPage(PDRectangle.A4); +// document.addPage(currentPage); +// cs = new PDPageContentStream(document, currentPage); +// currentY = PDRectangle.A4.getHeight() - TABLE_MARGIN; +// } +// +// drawImageGroup(cs, document, font, wrappedTitleLines, validUrls, currentY, +// Math.max(totalHeight, titleHeight)); +// currentY -= Math.max(totalHeight, titleHeight); +// } +// } +// } +// } +//// +// } finally { +// cs.close(); +// } +// // 将PDF保存到ByteArrayOutputStream +// document.save(pdfBaos); +// +//// ByteArrayOutputStream baos = new ByteArrayOutputStream(); +//// document.save(baos); +//// outputStream.flush(); +//// baos.writeTo(outputStream); +// +// +// } +// // 创建ZIP压缩包并将PDF写入输出流 +// try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) { +// // 设置最高压缩级别 +// zipOut.setLevel(Deflater.BEST_COMPRESSION); +// // 创建ZIP条目 +// ZipEntry entry = new ZipEntry(entity.getUserName()+entity.getCommunityName()+entity.getBuildingUnit()+entity.getRoomNo()+".pdf"); +// zipOut.putNextEntry(entry); +// +// // 将PDF数据写入ZIP +// byte[] pdfBytes = pdfBaos.toByteArray(); +// zipOut.write(pdfBytes, 0, pdfBytes.length); +// +// // 关闭当前条目 +// zipOut.closeEntry(); +// } +// } + // 加载字体,确保使用正确的文档实例 private static PDType0Font loadFont(PDDocument document) throws IOException { // 尝试多个可能的字体路径 @@ -266,7 +423,7 @@ public class PDFGenerator { if (text == null || text.isEmpty()) return lines; // 优化的文本换行逻辑,减少计算量 - int maxCharsPerLine = (int)(maxWidth / (FONT_SIZE * 0.4f)); // 调整字符估算系数 + int maxCharsPerLine = (int) (maxWidth / (FONT_SIZE * 0.4f)); // 调整字符估算系数 if (text.length() <= maxCharsPerLine) { lines.add(text); @@ -415,7 +572,7 @@ public class PDFGenerator { // 单图片模式:一页两行,每行占半页高度 float singleImageHeight = imageAvailableHeight; // 绘制标题(垂直居中) - float titleY = startY - totalHeight/2 + (titleLines.size() * LINE_HEIGHT)/2; + float titleY = startY - totalHeight / 2 + (titleLines.size() * LINE_HEIGHT) / 2; // 绘制第一行标题(顶部) // float titleY = startY - CELL_PADDING - FONT_SIZE; cs.beginText(); @@ -449,7 +606,7 @@ public class PDFGenerator { float imageHeightPer = (imageAvailableHeight - CELL_PADDING) / 2; // 绘制标题(垂直居中) - float titleY = startY - totalHeight/2 + (titleLines.size() * LINE_HEIGHT)/2; + float titleY = startY - totalHeight / 2 + (titleLines.size() * LINE_HEIGHT) / 2; cs.beginText(); cs.setFont(font, FONT_SIZE); cs.newLineAtOffset(TABLE_MARGIN + CELL_PADDING, titleY); @@ -536,7 +693,7 @@ public class PDFGenerator { TABLE_MARGIN + LEFT_COL_WIDTH + CELL_PADDING + imageWidthPer + CELL_PADDING, startY - CELL_PADDING - scaledHeight2, scaledWidth2, scaledHeight2);*/ - }else { + } else { // 多图片模式(超过2张图片):垂直堆叠显示,与双图片模式保持一致的样式 float imageHeightPer = (imageAvailableHeight - CELL_PADDING * (imageUrls.size() - 1)) / imageUrls.size(); @@ -587,7 +744,7 @@ public class PDFGenerator { } -// private static void drawImageGroup(PDPageContentStream cs, PDDocument doc, PDType0Font font, + // private static void drawImageGroup(PDPageContentStream cs, PDDocument doc, PDType0Font font, // List titleLines, List imageUrls, // float startY, float totalHeight) throws IOException { // // 绘制单元格边框 @@ -773,14 +930,14 @@ public class PDFGenerator { float maxWidth, float maxHeight) throws IOException { if (imageUrls.isEmpty()) return 0; - // return maxHeight; + // return maxHeight; if (imageUrls.size() == 1) { // 单图片模式:占用半页高度 return maxHeight / 2; - } else if(imageUrls.size() == 2){ + } else if (imageUrls.size() == 2) { // 双图片模式:整页高度 return maxHeight; - }else { + } else { // 多图片模式:根据图片数量动态计算高度 // 每张图片预留最小高度,防止页面过长 float minImageHeight = 50f; // 每张图片最小高度 @@ -798,7 +955,7 @@ public class PDFGenerator { } // 截断超长文本 - private static String truncateText(PDType0Font font,String text, float maxWidth) throws IOException { + private static String truncateText(PDType0Font font, String text, float maxWidth) throws IOException { // PDType0Font font = ...; // 获取字体对象 StringBuilder sb = new StringBuilder(); float currentWidth = 0; @@ -824,8 +981,8 @@ public class PDFGenerator { } // 简单估算:假设每个中文字符宽度等于字体大小 - int charsPerLine = (int)(maxWidth / fontSize); - int lineCount = (int)Math.ceil((double)text.length() / charsPerLine); + int charsPerLine = (int) (maxWidth / fontSize); + int lineCount = (int) Math.ceil((double) text.length() / charsPerLine); return lineCount * fontSize * 1.2f; // 行间距1.2倍 } @@ -838,7 +995,7 @@ public class PDFGenerator { cs.setLeading(fontSize * 1.2f); // 行间距 // 简单换行实现 - int charsPerLine = (int)(maxWidth / (fontSize * 0.8)); // 中文字符估算 + int charsPerLine = (int) (maxWidth / (fontSize * 0.8)); // 中文字符估算 int pos = 0; float currentY = startY; @@ -855,6 +1012,7 @@ public class PDFGenerator { currentY -= fontSize * 1.2f; } } + // 图片高度预估方法 private static float estimateImageHeight(String imageUrl, float targetWidth) throws IOException { try (InputStream is = new URL(imageUrl).openStream()) { @@ -992,8 +1150,6 @@ public class PDFGenerator { }*/ - - private static void drawTable(PDPageContentStream cs, PDType0Font font, float x, float y, String[][] data, float[] colWidths) throws IOException { @@ -1018,7 +1174,7 @@ public class PDFGenerator { // 绘制列分隔线 float currentX = x; for (int i = 1; i < colWidths.length; i++) { - currentX += colWidths[i-1]; + currentX += colWidths[i - 1]; cs.moveTo(currentX, y); cs.lineTo(currentX, y - ROW_HEIGHT * data.length); cs.stroke(); @@ -1075,7 +1231,7 @@ public class PDFGenerator { cs.stroke(); // 垂直居中文本(改进算法) - float textY = startY - rowHeight/2 + FONT_SIZE/2; + float textY = startY - rowHeight / 2 + FONT_SIZE / 2; //String title = "安装完成探测器工作图片\n检测时间:2025-08-14"; /* if(title.contains("\n")){ @@ -1083,7 +1239,7 @@ public class PDFGenerator { textY = startY - rowHeight/2 + FONT_SIZE/2 + (lines.length-1)*FONT_SIZE/2; }*/ drawCenteredText(cs, font, FONT_SIZE, title, - startX + LEFT_COL_WIDTH/2, textY); + startX + LEFT_COL_WIDTH / 2, textY); // 绘制图片(带5pt边距) cs.drawImage(image, diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java index ec35a8f..9bb72f3 100644 --- a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/controller/DeviceInstallInfoController.java @@ -37,6 +37,8 @@ import cc.iotkit.common.utils.MapstructUtils; import cc.iotkit.data.manager.IDeviceInstallInfoData; import cc.iotkit.manager.config.GasInstallationPDFGenerator; import cc.iotkit.manager.config.PDFGenerator; +import cc.iotkit.manager.dto.bo.BatchPdfWrapper; +import cc.iotkit.manager.dto.bo.ExportTask; import cc.iotkit.manager.dto.bo.device.DeviceDetectorQueryBo; import cc.iotkit.manager.dto.bo.device.DeviceInstallInfoQueryBo; import cc.iotkit.manager.dto.bo.device.DeviceQueryBo; @@ -100,6 +102,11 @@ import java.net.URLEncoder; import java.security.SecureRandom; import java.util.Collections; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.zip.Deflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import static cc.iotkit.data.model.QTbDeviceInstallInfo.tbDeviceInstallInfo; import static com.itextpdf.kernel.pdf.PdfName.*; @@ -116,6 +123,12 @@ public class DeviceInstallInfoController { @Autowired private IDeviceInstallInfoData iDeviceInstallInfoData; + @Autowired + private ExecutorService taskExecutor; + + // 存储任务状态 + private static final ConcurrentHashMap exportTasks = new ConcurrentHashMap<>(); + @ApiOperation(value = "安装列表", notes = "设备列表", httpMethod = "POST") //@SaCheckPermission("iot:device:query") @PostMapping("/page") @@ -201,6 +214,57 @@ public class DeviceInstallInfoController { PDFGenerator.generateInstallationPDF(data, response.getOutputStream()); } + + @PostMapping("/getPdfBatch") + @SaCheckPermission("device:install:upload") + public void getPdfBatch(@Validated @RequestBody Request request, HttpServletResponse response) throws Exception { + List ids = request.getData().getData(); + if (ids == null || ids.isEmpty()) { + throw new BizException(ErrCode.PARAMS_EXCEPTION); + } + + response.setContentType("application/zip"); + response.setHeader("Content-Disposition", "attachment; filename=\"批量安装信息.zip\""); + + // 创建ZIP输出流 + try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) { + zipOut.setLevel(Deflater.BEST_COMPRESSION); + + for (String id : ids) { + DeviceInstallInfo data = iDeviceInstallInfoData.findById(id); + if (data == null) { + continue; // 跳过不存在的记录 + } + + // 生成PDF字节数组 + ByteArrayOutputStream pdfBaos = new ByteArrayOutputStream(); + PDFGenerator.generateInstallationPDFBytes(data, pdfBaos); + byte[] pdfBytes = pdfBaos.toByteArray(); + + // 创建ZIP条目 + String fileName = data.getUserName() + "_" + + data.getCommunityName() + "_" + + data.getBuildingUnit() + data.getRoomNo() + ".pdf"; + // 清理文件名中的非法字符 + fileName = fileName.replaceAll("[\\\\/:*?\"<>|]", "_"); + + ZipEntry entry = new ZipEntry(fileName); + zipOut.putNextEntry(entry); + zipOut.write(pdfBytes, 0, pdfBytes.length); + zipOut.closeEntry(); + } + + zipOut.finish(); + } + } + + + + + + + + @ApiOperation("导出设备列表") @Log(title = "导出设备列表", businessType = BusinessType.EXPORT) // @SaCheckPermission("system:user:export")@RequestBody Request diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/BatchExportRequest.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/BatchExportRequest.java new file mode 100644 index 0000000..6fc64a9 --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/BatchExportRequest.java @@ -0,0 +1,11 @@ +package cc.iotkit.manager.dto.bo; + +import lombok.Data; + +import java.util.List; + +@Data +public class BatchExportRequest { + private List data; + private Long tenantId; +} diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/BatchPdfWrapper.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/BatchPdfWrapper.java new file mode 100644 index 0000000..778bffe --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/BatchPdfWrapper.java @@ -0,0 +1,11 @@ +package cc.iotkit.manager.dto.bo; + +import lombok.Data; + +import java.util.List; + +@Data +public class BatchPdfWrapper { + private List data; + private Long tenantId; +} diff --git a/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/ExportTask.java b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/ExportTask.java new file mode 100644 index 0000000..fa6aa98 --- /dev/null +++ b/iot-module/iot-manager/src/main/java/cc/iotkit/manager/dto/bo/ExportTask.java @@ -0,0 +1,28 @@ +package cc.iotkit.manager.dto.bo; + +import lombok.Data; + +import java.util.Date; +import java.util.List; + +// 任务状态类 +@Data +public class ExportTask { + private String taskId; + private List ids; + private String status; // PENDING, PROCESSING, COMPLETED, FAILED + private String filePath; + private String errorMessage; + private Date createTime; + private Date completeTime; + private int progress; // 进度 0-100 + + public ExportTask(String taskId, List ids, String status) { + this.taskId = taskId; + this.ids = ids; + this.status = status; + this.createTime = new Date(); + this.progress = 0; + } +} + diff --git a/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java b/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java index dc826ab..e3a7740 100644 --- a/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java +++ b/iot-module/iot-plugin/iot-plugin-main/src/main/java/cc/iotkit/plugin/main/ThingServiceImpl.java @@ -402,7 +402,7 @@ public class ThingServiceImpl implements IThingService { .deptAreaId(device.getDeptAreaId()) .readFlg(false) .alertTime(System.currentTimeMillis()) - .details("您的设备【" + device.getDeviceName() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。") + .details("您的设备【" + device.getDeviceName() + "】,位置【" + device.getSite() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。") .build()); // if (ObjectUtil.isNotEmpty(deviceInfoArrayList1)) { // for (int j = 0; j < deviceInfoArrayList1.size(); j++) { @@ -451,7 +451,7 @@ public class ThingServiceImpl implements IThingService { .deptAreaId(device.getDeptAreaId()) .readFlg(false) .alertTime(System.currentTimeMillis()) - .details("您的设备【" + device.getDeviceName() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。") + .details("您的设备【" + device.getDeviceName() + "】,位置【" + device.getSite() + "】触发事件 事件类型为:【" + map.get("eventTypeValue").toString() + "】。") .build()); // if (ObjectUtil.isNotEmpty(deviceInfoArrayList1)) { // for (int j = 0; j < deviceInfoArrayList1.size(); j++) { diff --git a/iot-starter/src/main/java/cc/iotkit/config/SchedulerConfig.java b/iot-starter/src/main/java/cc/iotkit/config/SchedulerConfig.java index 812a1d0..a68c126 100644 --- a/iot-starter/src/main/java/cc/iotkit/config/SchedulerConfig.java +++ b/iot-starter/src/main/java/cc/iotkit/config/SchedulerConfig.java @@ -28,6 +28,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + @Configuration @EnableScheduling public class SchedulerConfig { @@ -41,4 +44,10 @@ public class SchedulerConfig { return scheduler; } -} \ No newline at end of file + @Bean + public ExecutorService taskExecutor() { + // 创建一个固定大小的线程池,大小为10 + return Executors.newFixedThreadPool(10); + } + +} diff --git a/iot-starter/src/main/resources/application-dev.yml b/iot-starter/src/main/resources/application-dev.yml index aa528ba..388d7ba 100644 --- a/iot-starter/src/main/resources/application-dev.yml +++ b/iot-starter/src/main/resources/application-dev.yml @@ -60,7 +60,7 @@ spring: type: com.zaxxer.hikari.HikariDataSource driverClassName: com.mysql.cj.jdbc.Driver # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 - url: jdbc:mysql://123.57.78.108:3306/hma_iot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false + url: jdbc:mysql://172.16.0.64:3306/hma_iot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false # url: jdbc:mysql://123.57.78.108:3306/hma_iot_test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&useSSL=false username: root password: 1093e4769496a6ed @@ -83,7 +83,8 @@ spring: rest: #使用内置es的配置 #uris: http://elasticsearch:9200 - uris: http://123.57.78.108:9301 +# uris: http://123.57.78.108:9301 + uris: http://172.16.0.64:9301 username: elastic password: hmkj@2023 connection-timeout: 10s @@ -111,7 +112,8 @@ spring: embedded: enabled: false #host: redis - host: 123.57.78.108 +# host: 123.57.78.108 + host: 172.16.0.64 port: 6379 database: 11 password: HMkj@2023 diff --git a/iot-starter/src/main/resources/logback.xml b/iot-starter/src/main/resources/logback.xml index a4a1702..270d2aa 100644 --- a/iot-starter/src/main/resources/logback.xml +++ b/iot-starter/src/main/resources/logback.xml @@ -72,6 +72,12 @@ + + + + + + @@ -86,4 +92,4 @@ - \ No newline at end of file +