检验报告改A5
This commit is contained in:
@@ -17,35 +17,15 @@ import com.dpkj.modules.print.enums.MS439TonerStatusEnum;
|
||||
import com.dpkj.modules.print.request.MS439Request;
|
||||
import com.dpkj.modules.print.service.MS439PrintService;
|
||||
import com.dpkj.modules.print.utils.FolderUtils;
|
||||
import com.dpkj.modules.print.utils.FontLoader;
|
||||
import com.dpkj.modules.print.utils.PDFUtils;
|
||||
import com.dpkj.modules.print.utils.TemplateUtil;
|
||||
import com.dpkj.modules.print.vo.PrinterParam;
|
||||
import com.dpkj.modules.print.vo.PrinterStatus;
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.PageSize;
|
||||
import com.itextpdf.text.pdf.BaseFont;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
|
||||
import com.itextpdf.tool.xml.XMLWorkerHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
import org.thymeleaf.context.Context;
|
||||
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
|
||||
import org.thymeleaf.templatemode.TemplateMode;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -244,9 +224,9 @@ public class MS439PrintServiceImpl implements MS439PrintService {
|
||||
// 2. 准备模板数据
|
||||
Map<String, Object> data = prepareReportData(params);
|
||||
// 3. 渲染Thymeleaf模板
|
||||
String htmlContent = renderThymeleafTemplate(data);
|
||||
String htmlContent = TemplateUtil.renderThymeleafTemplate(data, "reportJY");
|
||||
// 4. 生成PDF文件
|
||||
createPdfFromHtml(htmlContent, pdfPath);
|
||||
TemplateUtil.createPdfFromHtml(htmlContent, pdfPath);
|
||||
|
||||
return pdfPath;
|
||||
} catch (Exception e) {
|
||||
@@ -275,74 +255,61 @@ public class MS439PrintServiceImpl implements MS439PrintService {
|
||||
}
|
||||
}
|
||||
|
||||
private void createPdfFromHtml(String html, String outputPath)
|
||||
throws IOException, DocumentException {
|
||||
|
||||
// 大小为A4纸
|
||||
Document document = new Document(PageSize.A4);
|
||||
try (OutputStream os = Files.newOutputStream(Paths.get(outputPath))) {
|
||||
PdfWriter writer = PdfWriter.getInstance(document, os);
|
||||
document.open();
|
||||
|
||||
// 加载自定义字体
|
||||
BaseFont simfangFont = FontLoader.loadFont("/font/simfang.ttf");
|
||||
|
||||
// 创建自定义字体提供器
|
||||
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {
|
||||
@Override
|
||||
public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) {
|
||||
return new Font(simfangFont, size, style, color);
|
||||
}
|
||||
};
|
||||
|
||||
// 解析 HTML 并生成 PDF
|
||||
XMLWorkerHelper.getInstance().parseXHtml(
|
||||
writer, document,
|
||||
new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)),
|
||||
null, StandardCharsets.UTF_8,
|
||||
fontProvider // 注入字体提供器
|
||||
);
|
||||
document.close(); // 这里关闭,确保 OutputStream 还没被关闭
|
||||
}
|
||||
}
|
||||
|
||||
// 模板渲染方法(保持不变)
|
||||
private String renderThymeleafTemplate(Map<String, Object> data) {
|
||||
// 设置模板数据
|
||||
Context context = new Context();
|
||||
context.setVariables(data);
|
||||
|
||||
// 填充数据到html
|
||||
TemplateEngine templateEngine = new TemplateEngine();
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setPrefix("classpath:/templates/");
|
||||
resolver.setSuffix(".html");
|
||||
resolver.setTemplateMode(TemplateMode.HTML);
|
||||
resolver.setCacheable(true);
|
||||
resolver.setApplicationContext(new AnnotationConfigReactiveWebApplicationContext());
|
||||
templateEngine.setTemplateResolver(resolver);
|
||||
return templateEngine.process("reportJY", context);
|
||||
}
|
||||
|
||||
// 报告数据准备(根据实际业务实现)
|
||||
private Map<String, Object> prepareReportData(JSONObject params) {
|
||||
public static Map<String, Object> prepareReportData(JSONObject params) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
// 基本信息
|
||||
Map<String, String> baseInfo = new HashMap<>();
|
||||
baseInfo.put("reportId", params.getString("reportId"));// 报告id(标本编号)
|
||||
baseInfo.put("lspcmName", params.getString("lspcmName"));// 标本名称
|
||||
|
||||
// 报告信息
|
||||
JSONObject printInfo = params.getJSONObject("print_info");
|
||||
baseInfo.put("reportId", printInfo.getString("reportId"));// 报告id(标本编号)
|
||||
baseInfo.put("lspcmName", printInfo.getString("lspcmName"));// 标本名称
|
||||
baseInfo.put("citemContent", printInfo.getString("citemContent"));// 申请内容
|
||||
baseInfo.put("examTime", printInfo.getString("examTime")); // 检验时间
|
||||
baseInfo.put("applyTime", printInfo.getString("applyTime"));// 申请时间
|
||||
baseInfo.put("spcmClctTime", printInfo.getString("spcmClctTime")); // 采集时间
|
||||
baseInfo.put("reportTime", printInfo.getString("reportTime")); // 报告时间
|
||||
baseInfo.put("chkTime", printInfo.getString("reportTime")); // 报告审核时间
|
||||
|
||||
// 患者信息
|
||||
JSONObject patInfo = params.getJSONObject("pat_info");
|
||||
baseInfo.put("patName", patInfo.getString("pat_name"));// 姓名
|
||||
baseInfo.put("patSex", patInfo.getString("pat_sex"));// 性别
|
||||
baseInfo.put("patAge", patInfo.getString("pat_age"));// 年龄
|
||||
baseInfo.put("patHomePhno", patInfo.getString("pat_home_phno"));// 电话
|
||||
baseInfo.put("idno", patInfo.getString("idno"));// 身份证号
|
||||
baseInfo.put("outpno", patInfo.getString("outpno"));// 门诊号
|
||||
baseInfo.put("inpno", patInfo.getString("inpno"));// 住院号
|
||||
baseInfo.put("contactsPhno", patInfo.getString("contacts_phno"));// 电话
|
||||
|
||||
// 就诊信息
|
||||
JSONObject pv1Info = params.getJSONObject("pv1_info");
|
||||
baseInfo.put("deptName", pv1Info.getString("dept_name"));// 科室
|
||||
baseInfo.put("inpWardName", pv1Info.getString("inp_ward_name"));// 病区名称
|
||||
baseInfo.put("inpBedNo", pv1Info.getString("inp_bed_no"));// 床号
|
||||
baseInfo.put("rgstNo", pv1Info.getString("rgst_no"));// 挂号单号
|
||||
String patVisitType = pv1Info.getString("pat_visit_type");
|
||||
if (StrUtil.isNotEmpty(patVisitType)) {
|
||||
if (StrUtil.equals("1", patVisitType)) {
|
||||
patVisitType = "门诊";
|
||||
} else if (StrUtil.equals("2", patVisitType)) {
|
||||
patVisitType = "住院";
|
||||
} else if (StrUtil.equals("4", patVisitType)) {
|
||||
patVisitType = "体检";
|
||||
}
|
||||
}
|
||||
baseInfo.put("patVisitType", patVisitType);// 就诊来源
|
||||
|
||||
|
||||
JSONObject applyInfoFirst = params.getJSONArray("apply_info").getJSONObject(0);
|
||||
baseInfo.put("placerName", applyInfoFirst.getString("placer_name"));// 申请医生
|
||||
baseInfo.put("placerName", applyInfoFirst.getString("placer_name"));// 开单医生
|
||||
baseInfo.put("spcmClctor", applyInfoFirst.getString("spcm_clctor"));// 标本采集人
|
||||
baseInfo.put("citemContent", params.getString("citemContent"));// 申请项目
|
||||
// baseInfo.put("applyTime", params.getString("apply_time"));// 开单时间
|
||||
// baseInfo.put("citemContent", params.getString("citemContent"));// 申请项目
|
||||
|
||||
data.put("baseInfo", baseInfo);
|
||||
|
||||
// 检验项目数据
|
||||
@@ -369,8 +336,13 @@ public class MS439PrintServiceImpl implements MS439PrintService {
|
||||
return data;
|
||||
}
|
||||
|
||||
private void addItem(List<Map<String, Object>> items, String name,
|
||||
String value, String range, String unit, String method, String oaflag) {
|
||||
public static void addItem(List<Map<String, Object>> items,
|
||||
String name,
|
||||
String value,
|
||||
String range,
|
||||
String unit,
|
||||
String method,
|
||||
String oaflag) {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("loitemCname", name);// 项目名称
|
||||
item.put("orderRptResult", value);// 结果
|
||||
|
||||
100
src/main/java/com/dpkj/modules/print/utils/TemplateUtil.java
Normal file
100
src/main/java/com/dpkj/modules/print/utils/TemplateUtil.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package com.dpkj.modules.print.utils;
|
||||
|
||||
import com.itextpdf.text.BaseColor;
|
||||
import com.itextpdf.text.Document;
|
||||
import com.itextpdf.text.DocumentException;
|
||||
import com.itextpdf.text.Font;
|
||||
import com.itextpdf.text.PageSize;
|
||||
import com.itextpdf.text.Rectangle;
|
||||
import com.itextpdf.text.pdf.BaseFont;
|
||||
import com.itextpdf.text.pdf.PdfWriter;
|
||||
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
|
||||
import com.itextpdf.tool.xml.XMLWorkerHelper;
|
||||
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
import org.thymeleaf.context.Context;
|
||||
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
|
||||
import org.thymeleaf.templatemode.TemplateMode;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Auther: 萧道子
|
||||
* @Date: 2025/11/7 14:50
|
||||
* @Description:
|
||||
*/
|
||||
public class TemplateUtil {
|
||||
|
||||
/**
|
||||
* 渲染Thymeleaf模板
|
||||
*
|
||||
* @param data : 数据
|
||||
* @param fileName : 模板文件名
|
||||
* @return java.lang.String
|
||||
* @author 萧道子 2025/11/7
|
||||
*/
|
||||
public static String renderThymeleafTemplate(Map<String, Object> data, String fileName) {
|
||||
// 设置模板数据
|
||||
Context context = new Context();
|
||||
context.setVariables(data);
|
||||
|
||||
// 填充数据到html
|
||||
TemplateEngine templateEngine = new TemplateEngine();
|
||||
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
|
||||
resolver.setPrefix("classpath:/templates/");
|
||||
resolver.setSuffix(".html");
|
||||
resolver.setTemplateMode(TemplateMode.HTML);
|
||||
resolver.setCacheable(true);
|
||||
resolver.setApplicationContext(new AnnotationConfigReactiveWebApplicationContext());
|
||||
templateEngine.setTemplateResolver(resolver);
|
||||
return templateEngine.process(fileName, context);
|
||||
}
|
||||
|
||||
|
||||
public static void createPdfFromHtml(String html, String outputPath) throws IOException, DocumentException {
|
||||
createPdfFromHtml(html, outputPath, PageSize.A4);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Html转为图片
|
||||
*
|
||||
* @param html :
|
||||
* @param outputPath :
|
||||
* @return void
|
||||
* @author 萧道子 2025/11/7
|
||||
*/
|
||||
public static void createPdfFromHtml(String html, String outputPath, Rectangle size) throws IOException, DocumentException {
|
||||
// 大小为A4纸
|
||||
Document document = new Document(size);
|
||||
try (OutputStream os = Files.newOutputStream(Paths.get(outputPath))) {
|
||||
PdfWriter writer = PdfWriter.getInstance(document, os);
|
||||
document.open();
|
||||
|
||||
// 加载自定义字体
|
||||
BaseFont simfangFont = FontLoader.loadFont("/font/simfang.ttf");
|
||||
|
||||
// 创建自定义字体提供器
|
||||
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider() {
|
||||
@Override
|
||||
public Font getFont(String fontname, String encoding, boolean embedded, float size, int style, BaseColor color) {
|
||||
return new Font(simfangFont, size, style, color);
|
||||
}
|
||||
};
|
||||
|
||||
// 解析 HTML 并生成 PDF
|
||||
XMLWorkerHelper.getInstance().parseXHtml(
|
||||
writer, document,
|
||||
new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)),
|
||||
null, StandardCharsets.UTF_8,
|
||||
fontProvider // 注入字体提供器
|
||||
);
|
||||
document.close(); // 这里关闭,确保 OutputStream 还没被关闭
|
||||
}
|
||||
}
|
||||
}
|
||||
148
src/main/resources/templates/reportJYA5.html
Normal file
148
src/main/resources/templates/reportJYA5.html
Normal file
@@ -0,0 +1,148 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>检验报告单</title>
|
||||
</head>
|
||||
<body>
|
||||
<div style="font-size: 12px;">
|
||||
<!-- 医院标题 -->
|
||||
<div style="text-align: center;">
|
||||
<div style="font-size: 14px; font-weight: bold;">
|
||||
澜沧拉祜族自治县中医医院<span th:text="${baseInfo.lspcmName}"></span>检验单
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--分隔-->
|
||||
<div style="height: 10px;"></div>
|
||||
<div style="background-color: #000;height: 1px;"></div>
|
||||
<div style="height: 5px;"></div>
|
||||
|
||||
<!-- 患者基本信息区域 - 使用表格布局以确保兼容 -->
|
||||
<table style="width: 100%;font-size: 12px;">
|
||||
<!-- 第1行:2个字段 -->
|
||||
<tr>
|
||||
<td style="width: 33%;font-weight: bold;">
|
||||
<span>患者姓名:</span>
|
||||
<span th:text="${baseInfo.patName}"></span>
|
||||
</td>
|
||||
<td style="width: 33%;font-weight: bold;">
|
||||
<span>患者性别:</span>
|
||||
<span th:text="${baseInfo.patSex}"></span>
|
||||
</td>
|
||||
<td style="width: 33%;font-weight: bold;">
|
||||
<span>患者年龄:</span>
|
||||
<span th:text="${baseInfo.patAge}"></span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- 第2行:3个字段 -->
|
||||
<tr>
|
||||
<td style="width: 33%;">
|
||||
<span>患者电话:</span>
|
||||
<span th:text="${baseInfo.contactsPhno}"></span>
|
||||
</td>
|
||||
<td style="width: 66%;"
|
||||
colspan="3">
|
||||
<span>身份证号:</span>
|
||||
<span th:text="${baseInfo.idno}"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 33%;">
|
||||
<span>就诊来源:</span>
|
||||
<span th:text="${baseInfo.patVisitType}"></span>
|
||||
</td>
|
||||
<td style="width: 33%;">
|
||||
<span>就诊科室:</span>
|
||||
<span th:text="${baseInfo.deptName}"></span>
|
||||
</td>
|
||||
<td style="width: 33%;">
|
||||
<span>挂号单号:</span>
|
||||
<span th:text="${baseInfo.rgstNo}"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 33%;">
|
||||
<span>门诊编号:</span>
|
||||
<span th:text="${baseInfo.outpno}"></span>
|
||||
</td>
|
||||
<td style="width: 33%;">
|
||||
<span>住院编号:</span>
|
||||
<span th:text="${baseInfo.inpno}"></span>
|
||||
</td>
|
||||
<td style="width: 33%;">
|
||||
<span>住院床号:</span>
|
||||
<span th:text="${baseInfo.inpBedNo}"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 33%;">
|
||||
<div>申请时间:</div>
|
||||
<div style="padding-top: 3px;"
|
||||
th:text="${baseInfo.applyTime}"></div>
|
||||
</td>
|
||||
<td style="width: 33%;">
|
||||
<div>检验时间:</div>
|
||||
<div style="padding-top: 3px;"
|
||||
th:text="${baseInfo.examTime}"></div>
|
||||
</td>
|
||||
<td style="width: 33%; ">
|
||||
<span>申请项目:</span>
|
||||
<span th:text="${baseInfo.citemContent}"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--分隔-->
|
||||
<div style="height: 10px;"></div>
|
||||
|
||||
<!-- 检测结果表格 -->
|
||||
<table style="border-collapse:collapse;width: 100%;border:1px solid gray;font-size: 12px;">
|
||||
<thead style="text-align: center;">
|
||||
<tr style="background-color: #f0f0f0;height:30px;">
|
||||
<th style="padding: 8px 5px; width: 25%;">项目名称</th>
|
||||
<th style="padding: 8px 5px; width: 20%;">结果</th>
|
||||
<th style="padding: 8px 5px; width: 15%;">单位</th>
|
||||
<th style="padding: 8px 5px; width: 20%;">参考区间</th>
|
||||
<th style="padding: 8px 5px; width: 20%;">测试方法</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody style="text-align: center;">
|
||||
<!-- 动态行渲染+异常值红色高亮 -->
|
||||
<tr th:each="item, stat : ${items}"
|
||||
th:style="${stat.index % 2 == 0} ? '' : 'background-color: #f0f0f0;'">
|
||||
<td style="padding: 8px 5px;"
|
||||
th:text="${item.loitemCname}"></td>
|
||||
<td style="padding: 8px 5px;">
|
||||
<span th:text="${item.orderRptResult}"></span>
|
||||
<span th:if="${item.oaflagLow}">↓</span>
|
||||
<span th:if="${item.oaflagHigh}">↑</span>
|
||||
</td>
|
||||
<td style="padding: 8px 5px;"
|
||||
th:text="${item.loitemUnit}"></td>
|
||||
<td style="padding: 8px 5px;"
|
||||
th:text="${item.loitemRv}"></td>
|
||||
<td style="padding: 8px 5px;"
|
||||
th:text="${item.inspectionMethod}"></td>
|
||||
</tr>
|
||||
<!-- 补齐空行 -->
|
||||
<!-- <tr th:each="i : ${#numbers.sequence(1, 10 - items.size())}" th:if="${items.size()} < 10">
|
||||
<td style="padding: 8px 5px;"> </td>
|
||||
<td style="padding: 8px 5px;"> </td>
|
||||
<td style="padding: 8px 5px;"> </td>
|
||||
<td style="padding: 8px 5px;"> </td>
|
||||
<td style="padding: 8px 5px;"> </td>
|
||||
</tr>-->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<!-- 建议与解释 -->
|
||||
<!--<div>
|
||||
<div style="padding-top: 10px;font-size: 12px;">
|
||||
建议与解释:
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user