diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 0dfdfd6..94be61d 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -23,6 +23,11 @@
8.0.4
pom
+
+ com.itextpdf
+ html2pdf
+ 4.0.5
+
org.apache.poi
poi-ooxml
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/docking/controller/SmartRemindersController.java b/ruoyi-admin/src/main/java/com/ruoyi/docking/controller/SmartRemindersController.java
index 78b7b4d..aa27227 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/docking/controller/SmartRemindersController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/docking/controller/SmartRemindersController.java
@@ -126,13 +126,13 @@ public class SmartRemindersController extends BaseController {
@PostMapping("/updateDq")
public AjaxResult updateDq(@RequestBody @Valid SmartReminders dq) throws SchedulerException, TaskException {
if (dq.getAlertType() == 2 || dq.getAlertType() == 3) {
- if (dq.getAlertManner() == 1) {
+ if (dq.getAlertManner() == 2) {
smartRemindersService.updateAndAdd(dq,false);
}else {
throw new ServiceException("参数错误!");
}
}else {
- if (dq.getAlertManner() == 2) {
+ if (dq.getAlertManner() == 1) {
smartRemindersService.updateById(dq);
}else {
throw new ServiceException("参数错误!");
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/docking/entity/request/SREnterRequest.java b/ruoyi-admin/src/main/java/com/ruoyi/docking/entity/request/SREnterRequest.java
index e2f2b70..e44a4d5 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/docking/entity/request/SREnterRequest.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/docking/entity/request/SREnterRequest.java
@@ -36,9 +36,9 @@ public class SREnterRequest {
private LocalDateTime alertTime;
/**
- * 提醒分类 1.全局自定义通知 2.申报任务即将结束(企业) 3.项目即将建设完成(政务) 4.项目自定义通知
+ * 提醒分类 1.全局自定义通知 2.项目即将结束(企业) 3.项目即将建设完成(政务) 4.项目自定义通知
*/
- @ApiModelProperty("提醒分类 1.全局自定义通知 2.申报任务即将结束(企业) 3.项目即将建设完成(政务) 4.项目自定义通知")
+ @ApiModelProperty("提醒分类 1.全局自定义通知 2.项目即将结束(企业) 3.项目即将建设完成(政务) 4.项目自定义通知")
private Integer alertType;
/**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/gysl/controller/GyslProjectHandbookController.java b/ruoyi-admin/src/main/java/com/ruoyi/gysl/controller/GyslProjectHandbookController.java
index 30aa4ae..4b21b66 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/gysl/controller/GyslProjectHandbookController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/gysl/controller/GyslProjectHandbookController.java
@@ -3,21 +3,16 @@ package com.ruoyi.gysl.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import com.itextpdf.kernel.pdf.PdfDocument;
-import com.itextpdf.kernel.pdf.PdfWriter;
-import com.itextpdf.layout.Document;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.gysl.entity.GyslProjectHandbook;
import com.ruoyi.gysl.service.GyslProjectHandbookService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
-import java.io.File;
import java.io.Serializable;
import static com.ruoyi.common.core.domain.AjaxResult.success;
@@ -112,6 +107,5 @@ public class GyslProjectHandbookController {
throws Exception {
gyslProjectHandbookService.generatePdfs(response,id);
}
-
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/GyslProjectHandbookService.java b/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/GyslProjectHandbookService.java
index 83f853c..c3a38d4 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/GyslProjectHandbookService.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/GyslProjectHandbookService.java
@@ -2,12 +2,11 @@ package com.ruoyi.gysl.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.itextpdf.layout.Document;
-import com.ruoyi.gysl.entity.BasicInformation;
import com.ruoyi.gysl.entity.GyslProjectHandbook;
-import com.ruoyi.gysl.entity.response.BasicInformationResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.FileNotFoundException;
+import java.io.IOException;
import java.net.MalformedURLException;
/**
@@ -22,25 +21,12 @@ public interface GyslProjectHandbookService extends IService basicInfoList);
-
- /**
- * 内容页设计
- */
- void addProductPages(Document document, java.util.List basicInfoList) throws MalformedURLException;
-
-
-
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/impl/GyslProjectHandbookServiceImpl.java b/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/impl/GyslProjectHandbookServiceImpl.java
index d52f3ec..6d0a9b6 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/impl/GyslProjectHandbookServiceImpl.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/gysl/service/impl/GyslProjectHandbookServiceImpl.java
@@ -1,20 +1,25 @@
package com.ruoyi.gysl.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.itextpdf.html2pdf.ConverterProperties;
+import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.ColorConstants;
-import com.itextpdf.kernel.colors.DeviceRgb;
+import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
+import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
+import com.itextpdf.kernel.utils.PdfMerger;
import com.itextpdf.layout.Document;
-import com.itextpdf.layout.element.*;
-import com.itextpdf.layout.properties.AreaBreakType;
+import com.itextpdf.layout.element.AreaBreak;
+import com.itextpdf.layout.element.Image;
+import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.HorizontalAlignment;
import com.itextpdf.layout.properties.TextAlignment;
-import com.itextpdf.layout.properties.UnitValue;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils;
@@ -27,9 +32,16 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
-import java.io.FileNotFoundException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
import java.net.MalformedURLException;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.rmi.ServerError;
import java.util.Arrays;
+import java.util.List;
/**
* 项目手册(GyslProjectHandbook)表服务实现类
@@ -44,163 +56,80 @@ public class GyslProjectHandbookServiceImpl extends ServiceImpl basicInfoList = basicInformationMapper.idListToProject
- (Arrays.asList(byId.getXmId().split(",")));
+ public void generatePdfs(HttpServletResponse response, Integer id) throws IOException {
+ // 获取数据
+ GyslProjectHandbook handbook = getById(id);
+ List basicInfoList = basicInformationMapper.idListToProject(
+ Arrays.asList(handbook.getXmId().split(",")));
+
// 设置响应头
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"product_catalog.pdf\"");
- try (
- // 直接绑定到 response 的输出流(不再生成本地文件)
- PdfDocument pdf = new PdfDocument(new PdfWriter(response.getOutputStream()));
- Document document = new Document(pdf)
- ) {
- addCoverPage(document, byId);
- addTableOfContents(document, basicInfoList);
- addProductPages(document, basicInfoList);
+
+ try (OutputStream outputStream = response.getOutputStream();
+ PdfWriter writer = new PdfWriter(outputStream);
+ PdfDocument mergedPdf = new PdfDocument(writer)) { // 主文档生命周期由外部try控制
+
+ // ========== 封面页 ==========
+ Document coverDoc = new Document(mergedPdf);
+ addCoverPage(coverDoc, handbook);
+ coverDoc.close(); // 关闭封面Document但不关闭PdfDocument
+
+ // ========== 动态内容合并 ==========
+ String htmlContent = "动态内容";
+ try (ByteArrayOutputStream tempStream = new ByteArrayOutputStream()) {
+ // HTML转PDF
+ HtmlConverter.convertToPdf(htmlContent, tempStream);
+ // 合并到主文档
+ try (PdfReader tempReader = new PdfReader(new ByteArrayInputStream(tempStream.toByteArray()));
+ PdfDocument tempPdf = new PdfDocument(tempReader)) {
+ PdfMerger merger = new PdfMerger(mergedPdf);
+ merger.merge(tempPdf, 1, tempPdf.getNumberOfPages());
+ }
+ }
+
} catch (Exception e) {
- response.reset(); // 清除已写入的内容
+ response.reset();
+ response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
- throw new RuntimeException("PDF生成失败", e);
+ throw new ServiceException("错误!");
}
}
- /**
- * 封面页设计
- */
@Override
- public void addCoverPage(Document document, GyslProjectHandbook gyslProjectHandbook) throws MalformedURLException {
- //添加手册名称
- Paragraph coverTitle = new Paragraph(gyslProjectHandbook.getName())
- .setFontSize(30)
- .setBold()
- .setFontColor(ColorConstants.BLUE)
+ public void addCoverPage(Document document, GyslProjectHandbook handbook) throws MalformedURLException {
+ // 标题
+ Paragraph title = new Paragraph(handbook.getName())
+ .setFontSize(30).setBold().setFontColor(ColorConstants.BLUE)
.setTextAlignment(TextAlignment.CENTER)
- .setMarginTop(200); // 垂直居中
- document.add(coverTitle);
- //添加副标题
- Paragraph ft = new Paragraph(gyslProjectHandbook.getSubtitle())
- .setFontSize(22)
- .setFontColor(ColorConstants.BLUE)
+ .setMarginTop(60);
+ document.add(title);
+
+ // 副标题
+ Paragraph subtitle = new Paragraph(handbook.getSubtitle())
+ .setFontSize(22).setFontColor(ColorConstants.BLUE)
.setTextAlignment(TextAlignment.RIGHT)
- .setMarginTop(300); // 垂直居中
- document.add(ft);
- //添加封面图片
- try {
- if (!FileUtils.checkAllowDownload(gyslProjectHandbook.getCoverImg())) {
- throw new ServiceException("资源文件({})非法! ");
- }
- // 本地资源路径
- String localPath = RuoYiConfig.getProfile();
- // 数据库资源地址
- String downloadPath = localPath + StringUtils.substringAfter(gyslProjectHandbook.getCoverImg(), Constants.RESOURCE_PREFIX);
- ImageData imageData = ImageDataFactory.create(downloadPath);
- Image image = new Image(imageData).setWidth(300).setHorizontalAlignment(HorizontalAlignment.CENTER);
- document.add(image);
- } catch (Exception e) {
- throw new ServiceException("下载文件失败! ");
+ .setMarginTop(70);
+ document.add(subtitle);
+
+ // 封面图片
+ String imgPath = RuoYiConfig.getProfile() +
+ StringUtils.substringAfter(handbook.getCoverImg(), Constants.RESOURCE_PREFIX);
+
+ if (!FileUtils.checkAllowDownload(imgPath)) {
+ throw new ServiceException("非法文件路径: " + imgPath);
}
- document.add(new AreaBreak()); // 强制分页
- }
- /**
- * 目录页设计
- */
- @Override
- public void addTableOfContents(Document document, java.util.List basicInfoList) {
- Paragraph tocTitle = new Paragraph("目录")
- .setFontSize(20)
- .setBold()
- .setTextAlignment(TextAlignment.CENTER);
- document.add(tocTitle);
- List tocList = new List()
- .setSymbolIndent(20);
- basicInfoList.forEach(x -> tocList.add(x.getBasicInformation().getName()));
- document.add(tocList);
- document.add(new AreaBreak(AreaBreakType.NEXT_PAGE));
- }
+ ImageData imageData = ImageDataFactory.create(imgPath);
+ Image image = new Image(imageData)
+ .setWidth(400)
+ .setMarginTop(85)
+ .setHorizontalAlignment(HorizontalAlignment.CENTER);
+ document.add(image);
- /**
- * 内容页设计
- */
- @Override
- public void addProductPages(Document document, java.util.List basicInfoList) throws MalformedURLException {
- basicInfoList.forEach(x -> {
- Paragraph chapter1 = new Paragraph(x.getBasicInformation().getName())
- .setFontSize(18)
- .setBold();
- document.add(chapter1);
- // 1. 添加园区信息表格
- Table parkTable = new Table(UnitValue.createPercentArray(new float[]{30, 70}))
- .setWidth(UnitValue.createPercentValue(100))
- .setMarginBottom(20)
- .setKeepTogether(true); // 保持表格在同一页;
- // 园区信息标题(蓝色背景)
- Cell cell = new Cell(1, 2)
- .setBackgroundColor(new DeviceRgb(33, 150, 243))
- .add(new Paragraph("园区信息")
- .setFontColor(DeviceRgb.WHITE)
- .setFontSize(16)
- .setBold())
- .setTextAlignment(TextAlignment.CENTER)
- .setPadding(8);
- parkTable.addCell(cell);
- // 添加园区信息行
- parkTable.addCell(new Cell().add(new Paragraph("总投资额")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("项目标签")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("项目标签")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("2.87万m²")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("现状分类")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("毛坯")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("重点发展产业")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("70个")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("建设模式")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("宿舍78间")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("所属功能区")).setPadding(5));
- parkTable.addCell(new Cell().add(new Paragraph("A栋18900m²,B栋5500m²整租价格可议")).setPadding(5));
- document.add(parkTable);
- // 2. 添加厂房信息表格
- Table factoryTable = new Table(UnitValue.createPercentArray(new float[]{25, 35, 35}))
- .setWidth(UnitValue.createPercentValue(100)).setKeepTogether(true); // 保持表格在同一页;
- // 厂房信息标题(蓝色背景)
- Cell cell2 = new Cell(1, 2)
- .setBackgroundColor(new DeviceRgb(33, 150, 243))
- .add(new Paragraph("厂房信息")
- .setFontColor(DeviceRgb.WHITE)
- .setFontSize(16)
- .setBold())
- .setTextAlignment(TextAlignment.CENTER)
- .setPadding(8);
- factoryTable.addCell(cell2);
- // 子标题(浅灰色背景)
- Cell z1 = new Cell()
- .setBackgroundColor(new DeviceRgb(245, 245, 245))
- .add(new Paragraph("A栋具体参数").setBold())
- .setTextAlignment(TextAlignment.CENTER)
- .setPadding(5);
- factoryTable.addCell(z1);
- Cell z2 = new Cell()
- .setBackgroundColor(new DeviceRgb(245, 245, 245))
- .add(new Paragraph("B栋具体参数").setBold())
- .setTextAlignment(TextAlignment.CENTER)
- .setPadding(5);
- factoryTable.addCell(z2);
- // 添加参数行
- factoryTable.addCell(new Cell().add(new Paragraph("租金")).setPadding(5));
- factoryTable.addCell(new Cell().add(new Paragraph("首层35元/m²,2-3层30元/m²,4-9层25元/m²")).setPadding(5));
- factoryTable.addCell(new Cell().add(new Paragraph("首层32元/m²,2-3层26元/m²,4-5层25元/m²")).setPadding(5));
- factoryTable.addCell(new Cell().add(new Paragraph("租金")).setPadding(5));
- factoryTable.addCell(new Cell().add(new Paragraph("首层35元/m²,2-3层30元/m²,4-9层25元/m²")).setPadding(5));
- factoryTable.addCell(new Cell().add(new Paragraph("首层32元/m²,2-3层26元/m²,4-5层25元/m²")).setPadding(5));
- document.add(factoryTable);
- });
+ // 分页控制(关键修改:直接操作PdfDocument)
+ document.getPdfDocument().addNewPage();
}
}
diff --git a/ruoyi-admin/src/main/resources/mapper/BasicInformationMapper.xml b/ruoyi-admin/src/main/resources/mapper/BasicInformationMapper.xml
index c4e74d5..e39165a 100644
--- a/ruoyi-admin/src/main/resources/mapper/BasicInformationMapper.xml
+++ b/ruoyi-admin/src/main/resources/mapper/BasicInformationMapper.xml
@@ -357,6 +357,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+
diff --git a/ruoyi-admin/src/main/resources/mapper/QyStatsMapper.xml b/ruoyi-admin/src/main/resources/mapper/QyStatsMapper.xml
index f6f31ea..f1aefea 100644
--- a/ruoyi-admin/src/main/resources/mapper/QyStatsMapper.xml
+++ b/ruoyi-admin/src/main/resources/mapper/QyStatsMapper.xml
@@ -3,30 +3,6 @@