dongdingding
杜函宇 1 week ago
parent dcf308dfe8
commit f7a0414b81

@ -23,6 +23,11 @@
<version>8.0.4</version> <!-- 2023年最新版本 -->
<type>pom</type>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>4.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>

@ -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("参数错误!");

@ -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;
/**

@ -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);
}
}

@ -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<GyslProjectHandbook
/**
* pdf
*/
void generatePdfs(HttpServletResponse response,Integer id) throws FileNotFoundException, MalformedURLException;
void generatePdfs(HttpServletResponse response,Integer id) throws IOException;
/**
*
*/
void addCoverPage(Document document, GyslProjectHandbook gyslProjectHandbook) throws MalformedURLException;
/**
*
*/
void addTableOfContents(Document document, java.util.List<BasicInformationResponse> basicInfoList);
/**
*
*/
void addProductPages(Document document, java.util.List<BasicInformationResponse> basicInfoList) throws MalformedURLException;
}

@ -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<ProjectHandBookM
private BasicInformationMapper basicInformationMapper;
/**
* pdf
*/
@Override
public void generatePdfs(HttpServletResponse response, Integer id) throws FileNotFoundException, MalformedURLException {
//获取当前手册信息
GyslProjectHandbook byId = getById(id);
//获取手册对应项目信息
java.util.List<BasicInformationResponse> basicInfoList = basicInformationMapper.idListToProject
(Arrays.asList(byId.getXmId().split(",")));
public void generatePdfs(HttpServletResponse response, Integer id) throws IOException {
// 获取数据
GyslProjectHandbook handbook = getById(id);
List<BasicInformationResponse> 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 = "<!DOCTYPE html><html><body style='font-family: SimSun;'>动态内容</body></html>";
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<BasicInformationResponse> 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<BasicInformationResponse> 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();
}
}

@ -357,6 +357,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<resultMap type="com.ruoyi.gysl.entity.BasicInformation" id="BasicInfor">
<result property="id" column="id"/>
<result property="name" column="name"/>
<result property="ztze" column="ztze"/>
<result property="label" column="label"/>
<result property="xzfl" column="xzfl"/>

@ -3,30 +3,6 @@
<mapper namespace="com.ruoyi.gysl.mapper.QyStatsMapper">
<select id="allProject" resultType="com.ruoyi.gysl.entity.stats.AllProjectResponse">
SELECT COUNT(*) AS allProject,
ROUND(IFNULL(SUM(b.zjzmj), 0) / 10000, 2) AS allGrossArea,
IFNULL(SUM(CASE WHEN a.xzfl = 1 THEN 1 ELSE 0 END), 0) AS allBuilding1,
IFNULL(SUM(CASE WHEN a.xzfl = 2 THEN 1 ELSE 0 END), 0) AS allBuilding2,
IFNULL(SUM(CASE WHEN a.xzfl = 3 THEN 1 ELSE 0 END), 0) AS allBuilding3,-- 当前年度统计
COUNT(CASE WHEN YEAR ( a.begain_time ) = YEAR ( CURRENT_DATE ()) THEN 1 END ) AS currentYearProject,
ROUND(
IFNULL(SUM(CASE WHEN YEAR ( a.begain_time ) = YEAR ( CURRENT_DATE ()) THEN b.zjzmj END ), 0) /
10000,
2
) AS currentYearGrossArea,
IFNULL(
SUM(CASE WHEN a.xzfl = 1 AND YEAR ( a.begain_time ) = YEAR ( CURRENT_DATE ()) THEN 1 ELSE 0 END ),
0
) AS currentYearBuilding1,
IFNULL(
SUM(CASE WHEN a.xzfl = 2 AND YEAR ( a.begain_time ) = YEAR ( CURRENT_DATE ()) THEN 1 ELSE 0 END ),
0
) AS currentYearBuilding2
FROM gysl_basic_information a
LEFT JOIN gysl_plan_information b ON a.id = b.xm_id
where a.tyshxydm = #{userName}
SELECT COUNT(*) AS allProject,
ROUND(IFNULL(SUM(b.zjzmj), 0) / 10000, 1) AS allGrossArea,
IFNULL(SUM(CASE WHEN a.xzfl = 1 THEN 1 ELSE 0 END), 0) AS allBuilding1,
@ -34,30 +10,23 @@
IFNULL(SUM(CASE WHEN a.xzfl = 3 THEN 1 ELSE 0 END), 0) AS allBuilding3,
<!-- 当前新开工项目数 -->
IFNULL(SUM(
<choose>
<when test="years != null and years != ''">
CASE WHEN LEFT(a.begain_time, 4) = #{years} THEN 1 ELSE 0 END
</when>
<otherwise>
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) THEN 1 ELSE 0 END
</otherwise>
</choose>
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) THEN 1 ELSE 0 END
), 0) AS currentYearProject,
<!-- 当年_建筑面积 -->
ROUND(IFNULL(SUM(
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) THEN b.zjzmj ELSE 0 END
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) THEN b.zjzmj ELSE 0 END
), 0)/10000,1) AS currentYearGrossArea,
<!-- 当年_已建数量 -->
IFNULL(SUM(
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) and a.xzfl = 1 THEN 1 ELSE 0 END
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) and a.xzfl = 1 THEN 1 ELSE 0 END
), 0) AS currentBuilding1,
<!-- 当年_在建数量 -->
IFNULL(SUM(
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) and a.xzfl = 2 THEN 1 ELSE 0 END
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) and a.xzfl = 2 THEN 1 ELSE 0 END
), 0) AS currentBuilding2,
<!-- 当年_拟建数量 -->
IFNULL(SUM(
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) and a.xzfl = 3 THEN 1 ELSE 0 END
CASE WHEN LEFT(a.begain_time, 4) = YEAR(NOW()) and a.xzfl = 3 THEN 1 ELSE 0 END
), 0) AS currentBuilding3
FROM gysl_basic_information a
LEFT JOIN gysl_plan_information b ON a.id = b.xm_id

Loading…
Cancel
Save