增加PDF的导出

master
yangzhe123 2025-07-23 09:45:10 +08:00
parent 6bc5762ef6
commit 98e069ac7e
7 changed files with 347 additions and 1 deletions

13
pom.xml
View File

@ -49,6 +49,19 @@
<dependencies> <dependencies>
<!-- iTextPDF核心库 - 用于PDF生成 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>7.2.5</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>7.2.5</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>

View File

@ -1,6 +1,10 @@
package com.whdc.controller; package com.whdc.controller;
import cn.hutool.http.HttpResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.whdc.model.dto.AutoCallDto; import com.whdc.model.dto.AutoCallDto;
import com.whdc.model.entity.AutoCallPerson; import com.whdc.model.entity.AutoCallPerson;
import com.whdc.model.entity.AutoCallTask; import com.whdc.model.entity.AutoCallTask;
@ -9,9 +13,15 @@ import com.whdc.service.AutoCallApiService;
import com.whdc.service.AutoCallTaskService; import com.whdc.service.AutoCallTaskService;
import com.whdc.service.AutoCallTaskService2; import com.whdc.service.AutoCallTaskService2;
import com.whdc.utils.ResultJson; import com.whdc.utils.ResultJson;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.text.ParseException; import java.text.ParseException;
import java.util.List; import java.util.List;
@ -88,4 +98,38 @@ public class AutoCallController {
autoCallTaskService.setCallIsPut(taskId); autoCallTaskService.setCallIsPut(taskId);
return ResultJson.ok(true); return ResultJson.ok(true);
} }
@PostMapping("/exportPdf")
public void exportPDF(@RequestBody AutoCallDto dto,
HttpServletResponse response,
HttpServletRequest request) {
Page<AutoCallTask> autoCallTaskPage = autoCallApiService.page3(dto);
List<AutoCallTask> records = autoCallTaskPage.getRecords();
ByteArrayInputStream pdfStream = autoCallApiService.exportPDF(records, response, dto.getStm(), dto.getEtm());
// 3. 设置响应头
try {
// 设置响应头
response.setContentType("application/pdf");
String fileName = "智能呼叫记录_" + dto.getStm().toString().replace(":", "-") + "_to_"
+ dto.getEtm().toString().replace(":", "-") + ".pdf";
// 获取User-Agent判断浏览器类型
String userAgent = request.getHeader("User-Agent");
// 针对不同浏览器设置不同的Content-Disposition
if (userAgent != null && userAgent.toLowerCase().contains("firefox")) {
// Firefox浏览器
response.setHeader("Content-Disposition",
"attachment; filename*=UTF-8''" + URLEncoder.encode(fileName, "UTF-8"));
} else {
// 其他浏览器(Chrome, Edge, Safari等)
response.setHeader("Content-Disposition",
"attachment; filename=\"" + new String(fileName.getBytes("GBK"), "ISO-8859-1") + "\"");
}
IOUtils.copy(pdfStream,response.getOutputStream());
response.flushBuffer();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} }

View File

@ -3,6 +3,7 @@ package com.whdc.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.whdc.model.entity.AutoCallPerson; import com.whdc.model.entity.AutoCallPerson;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@ -39,4 +40,9 @@ public interface AutoCallPersonMapper extends BaseMapper<AutoCallPerson> {
); );
return personCnt == failCnt; return personCnt == failCnt;
} }
List<AutoCallPerson> selectListByTaskId(@Param("taskId") Integer taskId);
String selectPositionByPhone(@Param("phone") String uploadNumber);
} }

View File

@ -76,4 +76,6 @@ public class AutoCallPerson {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(value = "__last_modify") @TableField(value = "__last_modify")
private Date detailLastModify; private Date detailLastModify;
@TableField(exist = false)
private String position;
} }

View File

@ -2,6 +2,21 @@ package com.whdc.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itextpdf.io.font.PdfEncodings;
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.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Div;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.whdc.mapper.*; import com.whdc.mapper.*;
import com.whdc.model.dto.AutoCallDto; import com.whdc.model.dto.AutoCallDto;
import com.whdc.model.entity.AutoCall; import com.whdc.model.entity.AutoCall;
@ -13,10 +28,16 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.ParseException; import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
/** /**
* @author lyf * @author lyf
* @since 2025-06-14 * @since 2025-06-14
@ -29,6 +50,8 @@ public class AutoCallApiService {
@Autowired @Autowired
private WarnCallMapMapper warnCallMapMapper; private WarnCallMapMapper warnCallMapMapper;
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public Page<AutoCallTask> page2(AutoCallDto dto) { public Page<AutoCallTask> page2(AutoCallDto dto) {
Date stm = null; Date stm = null;
Date etm = null; Date etm = null;
@ -141,7 +164,6 @@ public class AutoCallApiService {
} }
return wcmList; return wcmList;
} }
@Autowired @Autowired
private AutoCallTaskMapper taskMapper; private AutoCallTaskMapper taskMapper;
@Autowired @Autowired
@ -149,4 +171,239 @@ public class AutoCallApiService {
@Autowired @Autowired
private QXWarningMapper warningMapper; private QXWarningMapper warningMapper;
public Page<AutoCallTask> page3(AutoCallDto dto) {
Date stm = null;
Date etm = null;
try {
if (dto.getStm() != null && dto.getEtm() != null) {
stm = DateUtils.formatD(dto.getStm(), DateUtils.DATE_PATTERN1);
etm = DateUtils.formatD(dto.getEtm(), DateUtils.DATE_PATTERN1);
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
if (stm != null) stm = DateUtils.standardize(stm, true);
if (etm != null) etm = DateUtils.standardize(etm, false);
QueryWrapper<AutoCallTask> query = new QueryWrapper<AutoCallTask>()
.orderByDesc("id")
.between("warn_tm", stm, etm);
if (dto.getCallIsPut() != null) {
if (dto.getCallIsPut()) {
query.eq("status",
AutoCallTask.STATUS_ANY_SUCCESS
);
} else {
query.eq("status",
AutoCallTask.STATUS_ALL_FAIL
);
}
} else {
query.in("status",
AutoCallTask.STATUS_SHOULD_GENERATE,
AutoCallTask.STATUS_GENERATED,
AutoCallTask.STATUS_ANY_SUCCESS,
AutoCallTask.STATUS_ALL_FAIL,
AutoCallTask.STATUS_CANCELLED
);
}
Page pageParam = dto.getPage().getPage();
Page<AutoCallTask> pageResult = taskMapper.selectPage(
pageParam,
query
);
List<AutoCallTask> records = pageResult.getRecords();
if (records.size() > 0) {
for (AutoCallTask task : records) {
Integer taskId = task.getId();
List<AutoCallPerson> autoCallList = personMapper.selectList(
new QueryWrapper<AutoCallPerson>()
.eq("task_id", taskId)
);
for (AutoCallPerson autoCallPerson : autoCallList) {
String position = personMapper.selectPositionByPhone(autoCallPerson.getUploadNumber());
autoCallPerson.setPosition(position);
}
task.setCallList(autoCallList);
}
}
return pageResult;
}
/**
* pdf
* @param records
* @param response
* @param stm
* @param etm
* @return
*/
public ByteArrayInputStream exportPDF(List<AutoCallTask> records, HttpServletResponse response, String stm, String etm) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (PdfWriter writer = new PdfWriter(out);
// 设置A4横向宽297mm高210mm
PdfDocument pdfDoc = new PdfDocument(writer);
Document document = new Document(pdfDoc, PageSize.A4.rotate())) {
// 添加标题
String fontPath = "/fonts/ChineseFonts.ttf";
PdfFont font = PdfFontFactory.createFont(fontPath, PdfEncodings.IDENTITY_H);
document.setFont(font);
document.add(new Paragraph("智能呼叫记录报表")
.setFontSize(16)
.setBold()
.setTextAlignment(TextAlignment.CENTER)
.setMarginBottom(20));
// 创建头部布局(时间段和签名)
Div headerDiv = new Div().setMarginBottom(15);
float[] columnWidths1 = {1, 1};
Table layoutTable = new Table(columnWidths1)
.setWidth(UnitValue.createPercentValue(100))
.setMarginBottom(15);
Paragraph leftPara = new Paragraph(String.format("筛选时间段:%s 至 %s", stm, etm))
.setFontSize(12)
.setTextAlignment(TextAlignment.LEFT);
Paragraph rightPara = new Paragraph("值班人员签名________________________")
.setFontSize(12)
.setTextAlignment(TextAlignment.RIGHT);
layoutTable.addCell(new Cell().add(leftPara).setBorder(Border.NO_BORDER));
layoutTable.addCell(new Cell().add(rightPara).setBorder(Border.NO_BORDER));
document.add(layoutTable);
// 定义表格列宽适配横向A4新增字段列
float[] columnWidths = {
30, // 序号
150, // 预警名称
120, // 智能呼叫时间
100, // 县(市、区)
130, // 状态
59, // 通话时长(秒)
150, // 拨打时间
150, // 结束时间
100 // 呼叫对象及职务
};
Table table = new Table(columnWidths);
table.setSkipFirstHeader(false);
// 添加表头
addTableHeader(table);
// 添加数据行
addTableData(table, records);
document.add(table);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
return new ByteArrayInputStream(out.toByteArray());
}
// 更新表头(添加新字段)
private void addTableHeader(Table table) {
String[] headers = {
"序号",
"预警名称",
"智能呼叫时间",
"县(市、区)",
"状态",
"通话时长",
"拨打时间",
"结束时间",
"呼叫对象及职务"
};
for (String header : headers) {
table.addHeaderCell(new Cell()
.add(new Paragraph(header))
.setBackgroundColor(ColorConstants.LIGHT_GRAY)
.setTextAlignment(TextAlignment.CENTER));
}
}
// 更新数据行(适配新字段)
private void addTableData(Table table, List<AutoCallTask> records) {
int serialNumber = 1;
for (AutoCallTask record : records) {
// 拼接县(市、区)
String region = record.getWarnCtnm() + record.getWarnCnnm();
// 处理呼叫对象信息
StringBuilder callInfo = new StringBuilder();
for (AutoCallPerson item : record.getCallList()) {
String name = item.getUploadCustName() != null ? item.getUploadCustName() : "未知对象";
String position = item.getPosition() != null ? item.getPosition() : "无职务";
callInfo.append(name).append("").append(position).append("\n");
}
//处理通话时长
StringBuilder callTime = new StringBuilder();
for (AutoCallPerson item : record.getCallList()) {
String time = item.getDetailTalkTimes() != null? item.getDetailTalkTimes() + "秒" : "未知";
callTime.append(time).append("\n");
}
//处理状态
StringBuilder status = new StringBuilder();
for (AutoCallPerson item : record.getCallList()) {
String s = item.getDetailRemark() != null? item.getDetailRemark() : "未知";
status.append(s).append("\n");
}
//处理拨打时间
StringBuilder startTime = new StringBuilder();
for (AutoCallPerson item : record.getCallList()) {
String s = formatTime(item.getDetailStartedAt());
startTime.append(s).append("\n");
}
//处理结束拨打时间
StringBuilder endTime = new StringBuilder();
for (AutoCallPerson item : record.getCallList()) {
String s = formatTime(item.getDetailEndringAt());
endTime.append(s).append("\n");
}
// 格式化时间
String formattedCreateTime = formatTime(record.getCreateTm());
// 添加行数据
table.addCell(new Cell().add(new Paragraph(String.valueOf(serialNumber++)).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(record.getWarnName() != null ? record.getWarnName() : "").setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(formattedCreateTime).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(region).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(status.toString()).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(callTime.toString()).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(startTime.toString()).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(endTime.toString()).setFontSize(10)));
table.addCell(new Cell().add(new Paragraph(callInfo.toString()).setFontSize(10)));
}
}
// 新增时间格式化工具方法
private String formatTime(Object timeObj) {
if (timeObj == null) {
return "";
}
// 处理LocalDateTime类型
if (timeObj instanceof LocalDateTime) {
return ((LocalDateTime) timeObj).format(DATE_TIME_FORMATTER);
}
// 处理Date类型
else if (timeObj instanceof Date) {
LocalDateTime dateTime = new java.sql.Timestamp(
((Date) timeObj).getTime()
).toLocalDateTime();
return dateTime.format(DATE_TIME_FORMATTER);
}
// 处理其他可能的时间类型
else if (timeObj instanceof Long) { // 时间戳
LocalDateTime dateTime = new java.sql.Timestamp(
(Long) timeObj
).toLocalDateTime();
return dateTime.format(DATE_TIME_FORMATTER);
}
// 无法识别的类型直接返回字符串
return timeObj.toString();
}
} }

Binary file not shown.

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.whdc.mapper.AutoCallPersonMapper">
<select id="selectListByTaskId" resultType="com.whdc.model.entity.AutoCallPerson">
select T1.*,T2.POSITION as position from FXKH_TXL.AUTO_CALL_PERSON T1
LEFT JOIN FXKH_TXL.SH_ADDRESS_BOOK T2 ON T1.__NUMBER = T2.PHONE
where T1.TASK_ID = #{taskId}
</select>
<select id="selectPositionByPhone" resultType="String">
select t.POSITION
from FXKH_TXL.SH_ADDRESS_BOOK t
where
t.DEL = 1
AND t.PHONE = #{phone}
ORDER BY
t.SORT ASC
LIMIT 1
</select>
</mapper>