PhysicalCheckPDFUtil.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. package thyyxxk.wxservice_server.utils;
  2. import com.alibaba.fastjson.JSONArray;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.itextpdf.text.*;
  5. import com.itextpdf.text.pdf.*;
  6. import com.itextpdf.text.pdf.draw.LineSeparator;
  7. import lombok.extern.slf4j.Slf4j;
  8. import thyyxxk.wxservice_server.entity.ResultVo;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.File;
  11. import java.io.OutputStream;
  12. import java.net.URLEncoder;
  13. import java.nio.file.Files;
  14. import java.util.Map;
  15. import java.util.UUID;
  16. @Slf4j
  17. public class PhysicalCheckPDFUtil {
  18. private static final String PDF_PATH = "/home/medical-report-pdf/";
  19. private static final String LOGO_PATH = "/home/images/thyylogo.png";
  20. public static void createPDF(HttpServletResponse response, JSONObject tjIndex, JSONObject tjResult) {
  21. try {
  22. response.setContentType("application/x-download");
  23. response.addHeader("content-disposition", "attachment;filename="
  24. + URLEncoder.encode("长沙泰和医院体检报告.pdf", "UTF-8"));
  25. OutputStream outputStream = response.getOutputStream();
  26. makePdfFile(tjIndex, tjResult, outputStream);
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. throw new RuntimeException(e);
  30. }
  31. }
  32. public static ResultVo<String> savePdfToDisk(JSONObject tjIndex, JSONObject tjResult) {
  33. String today = DateUtil.today().replaceAll("-", "");
  34. String uid = UUID.randomUUID().toString().replaceAll("-", "");
  35. String fileName = today + uid + ".pdf";
  36. try {
  37. File pdfFile = new File(PDF_PATH + fileName);
  38. if (pdfFile.exists()) {
  39. pdfFile.delete();
  40. }
  41. OutputStream outputStream = Files.newOutputStream(pdfFile.toPath());
  42. makePdfFile(tjIndex, tjResult, outputStream);
  43. } catch (Exception e) {
  44. e.printStackTrace();
  45. }
  46. String downloadUrl = "https://staticweb.hnthyy.cn/medicalReport/" + fileName;
  47. log.info("生成体检报告下载链接:{}", downloadUrl);
  48. return ResultVoUtil.success();
  49. }
  50. private static void makePdfFile(JSONObject tjIndex, JSONObject tjResult, OutputStream outputStream) throws Exception {
  51. Document document = getDocument();
  52. PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream);
  53. document.open();
  54. document.add(getBarcodeParagraph(pdfWriter, tjIndex.getString("条码号")));
  55. BaseFont baseFont = BaseFont.createFont("STSong-Light","UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
  56. Font font = new Font(baseFont, 30, Font.BOLD);
  57. document.add(getTitleParagraph(font));
  58. document.add(getBriefContent(font, tjIndex));
  59. document.add(getFooter(baseFont));
  60. pdfWriter.setPageEvent(new PdfPageEventHelper() {
  61. @Override
  62. public void onStartPage(PdfWriter writer, Document document) {
  63. PdfContentByte pdfContentByte = writer.getDirectContent();
  64. pdfContentByte.saveState();
  65. pdfContentByte.beginText();
  66. pdfContentByte.setFontAndSize(baseFont, 10);
  67. // header
  68. float y = document.top(-20);
  69. pdfContentByte.showTextAligned(PdfContentByte.ALIGN_LEFT, "H-Left", document.left(), y, 0);
  70. pdfContentByte.showTextAligned(PdfContentByte.ALIGN_CENTER, "第" + writer.getPageNumber() + "页",
  71. (document.right() + document.left()) / 2, y, 0);
  72. pdfContentByte.showTextAligned(PdfContentByte.ALIGN_RIGHT, "H-Right", document.right(), y, 0);
  73. pdfContentByte.endText();
  74. LineSeparator line = new LineSeparator(1, 100, BaseColor.BLACK, Element.ALIGN_CENTER, 10);
  75. try {
  76. document.add(line);
  77. } catch (DocumentException e) {
  78. throw new RuntimeException(e);
  79. }
  80. pdfContentByte.restoreState();
  81. }
  82. });
  83. document.newPage();
  84. document.add(getEntryWord(font));
  85. document.add(getSummaryTitle(font));
  86. document.add(getSummaryContent(font, tjResult.getJSONObject("summary")));
  87. document.add(getSummaryFooter(font, tjResult.getJSONObject("summary")));
  88. document.newPage();
  89. JSONObject examResults = tjResult.getJSONObject("examResult");
  90. JSONArray checkItems = tjResult.getJSONArray("checkItems");
  91. if (!examResults.isEmpty() && !checkItems.isEmpty()) {
  92. addExamResult(baseFont, document, examResults, checkItems);
  93. }
  94. document.add(getTailPageLogo(baseFont));
  95. document.close();
  96. outputStream.close();
  97. }
  98. private static Document getDocument() {
  99. Document document = new Document(PageSize.A4);
  100. document.addAuthor("长沙泰和医院");
  101. document.addCreationDate();
  102. document.addSubject("体检报告");
  103. return document;
  104. }
  105. private static Barcode128 getBarcode(String tjid) {
  106. Barcode128 barcode128 = new Barcode128();
  107. barcode128.setSize(10);
  108. barcode128.setBarHeight(28);
  109. barcode128.setBaseline(10);
  110. barcode128.setCode(tjid);
  111. barcode128.setStartStopText(true);
  112. barcode128.setExtended(true);
  113. return barcode128;
  114. }
  115. private static Paragraph getBarcodeParagraph(PdfWriter pdfWriter, String tjid) {
  116. PdfContentByte pdfContentByte = new PdfContentByte(pdfWriter);
  117. Barcode128 barcode128 = getBarcode(tjid);
  118. Image barcodeImage = barcode128.createImageWithBarcode(pdfContentByte, null, null);
  119. Chunk barcodeChunk = new Chunk(barcodeImage, 420, -20, false);
  120. return new Paragraph(barcodeChunk);
  121. }
  122. private static Paragraph getTitleParagraph(Font font) {
  123. Paragraph titleParagraph = new Paragraph();
  124. Chunk titleChunkLine1 = new Chunk("长 沙 泰 和 医 院");
  125. titleChunkLine1.setFont(font);
  126. titleChunkLine1.setTextRise(-70);
  127. titleParagraph.add(titleChunkLine1);
  128. titleParagraph.add(Chunk.NEWLINE);
  129. Chunk titleChunkLine2 = new Chunk("体 检 报 告");
  130. titleChunkLine2.setFont(font);
  131. titleChunkLine2.setTextRise(-90);
  132. titleParagraph.setAlignment(Element.ALIGN_CENTER);
  133. titleParagraph.add(titleChunkLine2);
  134. return titleParagraph;
  135. }
  136. private static Paragraph getBriefContent(Font font, JSONObject tjIndex) {
  137. font.setSize(12);
  138. font.setStyle(Font.NORMAL);
  139. Paragraph paragraph = new Paragraph();
  140. paragraph.setAlignment(Element.ALIGN_LEFT);
  141. paragraph.setSpacingBefore(470);
  142. paragraph.setIndentationLeft(146);
  143. String personalFlag = tjIndex.getString("团体or个人");
  144. String psntext = personalFlag.equals("0") ? "[ ]个人 [√]团体" : "[√]个人 [ ]团体";
  145. Chunk tjidChunk = new Chunk("体检编号:" + tjIndex.getString("条码号") + " " + psntext);
  146. tjidChunk.setFont(font);
  147. paragraph.add(tjidChunk);
  148. paragraph.add(Chunk.NEWLINE);
  149. String gender = tjIndex.getString("性别").equals("1") ? "男" : "女";
  150. String name = tjIndex.getString("姓名");
  151. String age = tjIndex.getString("年龄");
  152. Chunk psnChunk = new Chunk("姓名:" + (null == name ? "" : name) + " 性别:"
  153. + gender + " 年龄:" + (null == age ? "" : age));
  154. psnChunk.setFont(font);
  155. paragraph.add(psnChunk);
  156. paragraph.add(Chunk.NEWLINE);
  157. String unit = tjIndex.getString("工作单位");
  158. Chunk unitChunk = new Chunk("单位:" + (null == unit ? "" : unit));
  159. unitChunk.setFont(font);
  160. paragraph.add(unitChunk);
  161. paragraph.add(Chunk.NEWLINE);
  162. String department = tjIndex.getString("所在部门");
  163. Chunk departmentChunk = new Chunk("部门:" + (null == department ? "" : department));
  164. departmentChunk.setFont(font);
  165. paragraph.add(departmentChunk);
  166. paragraph.add(Chunk.NEWLINE);
  167. String checkTime = tjIndex.getString("登记日期");
  168. if (null == checkTime) {
  169. checkTime = "";
  170. }
  171. if (StringUtil.notBlank(checkTime) && checkTime.length() >= 8) {
  172. checkTime = checkTime.substring(0, 4) + "-" + checkTime.substring(4, 6) + "-" + checkTime.substring(6);
  173. }
  174. String phone = tjIndex.getString("手机");
  175. Chunk dateChunk = new Chunk("体检日期:" + checkTime
  176. + " 电话:" + (null == phone ? "" : phone));
  177. dateChunk.setFont(font);
  178. paragraph.add(dateChunk);
  179. return paragraph;
  180. }
  181. private static Paragraph getFooter(BaseFont baseFont) {
  182. Font font = new Font(baseFont, 10, Font.NORMAL);
  183. Paragraph paragraph = new Paragraph();
  184. paragraph.setAlignment(Element.ALIGN_CENTER);
  185. paragraph.setSpacingBefore(100);
  186. LineSeparator line = new LineSeparator(1, 100, BaseColor.BLACK, Element.ALIGN_CENTER, 0);
  187. paragraph.add(line);
  188. paragraph.add(Chunk.NEWLINE);
  189. Chunk footerLine1 = new Chunk("长沙泰和医院");
  190. footerLine1.setFont(font);
  191. paragraph.add(footerLine1);
  192. paragraph.add(Chunk.NEWLINE);
  193. Chunk footerLine2 = new Chunk("咨询电话:0731-88518505");
  194. footerLine2.setFont(font);
  195. paragraph.add(footerLine2);
  196. paragraph.add(Chunk.NEWLINE);
  197. Chunk footerLine3 = new Chunk("本体检报告仅供临床参考,不作为诊断依据,谢谢您的光临!");
  198. footerLine3.setFont(new Font(baseFont, 12, Font.NORMAL));
  199. paragraph.add(footerLine3);
  200. return paragraph;
  201. }
  202. private static Paragraph getEntryWord(Font font) {
  203. font.setSize(12);
  204. Paragraph paragraph = new Paragraph();
  205. paragraph.setFont(font);
  206. paragraph.add(new Chunk("尊敬的客户:"));
  207. paragraph.add(Chunk.NEWLINE);
  208. paragraph.add(new Chunk(" 您好!欢迎您莅临长沙泰和医院体检中心。身体健康是学习和工作的基础,注意健康是生活和事业发展的必须。" +
  209. "世界卫生组织(WHO)提出:“健康是人的生理、心里和社会的完美状态,而不仅仅是指无疾病或非体弱的状态”。通过健康体检," +
  210. "检查和发现影响健康的有关因素,成为促进您身心健康的重要措施和保证。为了您的健康,我们真诚的建议您定期进行健康体检。"));
  211. return paragraph;
  212. }
  213. private static PdfPTable getSummaryTitle(Font font) {
  214. font.setSize(12);
  215. PdfPTable table = new PdfPTable(1);
  216. table.setSpacingBefore(20);
  217. table.setWidthPercentage(100);
  218. PdfPCell cell = new PdfPCell(new Paragraph("一、体检结论及健康建议", font));
  219. cell.setPaddingBottom(8);
  220. table.addCell(cell);
  221. return table;
  222. }
  223. private static PdfPTable getSummaryContent(Font font, JSONObject summary) {
  224. font.setSize(12);
  225. font.setStyle(Font.NORMAL);
  226. PdfPTable table = new PdfPTable(1);
  227. table.setWidthPercentage(100);
  228. table.setSplitLate(false);
  229. PdfPCell cell = new PdfPCell(new Paragraph(summary.getString("汇总建议"), font));
  230. cell.disableBorderSide(3);
  231. cell.setPaddingLeft(10);
  232. cell.setPaddingRight(10);
  233. table.addCell(cell);
  234. return table;
  235. }
  236. private static PdfPTable getSummaryFooter(Font font, JSONObject summary) {
  237. font.setSize(12);
  238. PdfPTable table = new PdfPTable(1);
  239. table.setWidthPercentage(100);
  240. table.setSplitLate(false);
  241. Paragraph paragraph = new Paragraph();
  242. paragraph.setFont(font);
  243. paragraph.add(new Chunk("汇总:" + summary.getString("汇总医生")));
  244. paragraph.add(Chunk.NEWLINE);
  245. paragraph.add(Chunk.NEWLINE);
  246. paragraph.add(new Chunk("主检:" + summary.getString("审核医生")));
  247. PdfPCell cell = new PdfPCell(paragraph);
  248. cell.disableBorderSide(1);
  249. cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
  250. cell.setPaddingRight(30);
  251. cell.setPaddingTop(15);
  252. cell.setPaddingBottom(15);
  253. table.addCell(cell);
  254. return table;
  255. }
  256. private static void addExamResult(BaseFont baseFont, Document document, JSONObject itemResults, JSONArray checkItems) throws Exception {
  257. int entryIndex = 0;
  258. Font font = new Font(baseFont, 12, Font.NORMAL);
  259. for (Map.Entry<String, Object> entry : itemResults.entrySet()) {
  260. Paragraph paragraph = new Paragraph();
  261. font.setColor(BaseColor.BLUE);
  262. paragraph.setFont(font);
  263. paragraph.setSpacingAfter(8);
  264. if (entryIndex > 0) {
  265. paragraph.setSpacingBefore(15);
  266. }
  267. paragraph.add(new Chunk(entry.getKey()));
  268. document.add(paragraph);
  269. font.setColor(BaseColor.BLACK);
  270. JSONArray results = (JSONArray) entry.getValue();
  271. String restype = results.getJSONObject(0).getString("结果类型");
  272. if (entry.getKey().equals("碳呼气试验") || restype.equals("3")) {
  273. restype = "3";
  274. for (int i = 0; i < results.size(); i++) {
  275. JSONObject item = results.getJSONObject(i);
  276. if (StringUtil.notBlank(item.getString("单位")) || StringUtil.notBlank(item.getString("参考范围显示效果"))) {
  277. restype = "2";
  278. break;
  279. }
  280. }
  281. }
  282. String sumContent = "";
  283. String examDoctor = "";
  284. String auditDoctor = "";
  285. for (int i = 0; i < checkItems.size(); i++) {
  286. JSONObject item = checkItems.getJSONObject(i);
  287. if (item.getString("name").equals(entry.getKey())) {
  288. sumContent = item.getString("诊断内容");
  289. examDoctor = item.getString("检查医生签名");
  290. auditDoctor = item.getString("审核医生签名");
  291. break;
  292. }
  293. }
  294. if (restype.equals("3") || restype.equals("2")) {
  295. PdfPTable table = new PdfPTable(4);
  296. table.setWidthPercentage(100);
  297. PdfPCell header1 = new PdfPCell(new Phrase("项目", font));
  298. header1.disableBorderSide(8);
  299. header1.setPaddingBottom(6);
  300. header1.setBackgroundColor(BaseColor.LIGHT_GRAY);
  301. PdfPCell header2 = new PdfPCell(new Phrase("体检结果", font));
  302. header2.disableBorderSide(12);
  303. header2.setPaddingBottom(6);
  304. header2.setBackgroundColor(BaseColor.LIGHT_GRAY);
  305. if (restype.equals("3")) {
  306. header2.setColspan(3);
  307. }
  308. table.addCell(header1);
  309. table.addCell(header2);
  310. if (restype.equals("2")) {
  311. PdfPCell header3 = new PdfPCell(new Phrase("单位", font));
  312. header3.disableBorderSide(12);
  313. header3.setPaddingBottom(6);
  314. header3.setBackgroundColor(BaseColor.LIGHT_GRAY);
  315. PdfPCell header4 = new PdfPCell(new Phrase("参考范围", font));
  316. header4.disableBorderSide(4);
  317. header4.setPaddingBottom(6);
  318. header4.setBackgroundColor(BaseColor.LIGHT_GRAY);
  319. table.addCell(header3);
  320. table.addCell(header4);
  321. }
  322. for (int i = 0; i < results.size(); i++) {
  323. JSONObject item = results.getJSONObject(i);
  324. PdfPCell res1 = new PdfPCell(new Phrase(item.getString("检查项目"), font));
  325. res1.disableBorderSide(8);
  326. res1.setPaddingBottom(6);
  327. PdfPCell res2 = new PdfPCell(new Phrase(item.getString("结果"), font));
  328. res2.disableBorderSide(12);
  329. res2.setPaddingBottom(6);
  330. if (restype.equals("3")) {
  331. res2.setColspan(3);
  332. }
  333. table.addCell(res1);
  334. table.addCell(res2);
  335. if (restype.equals("2")) {
  336. PdfPCell res3 = new PdfPCell(new Phrase(item.getString("单位"), font));
  337. res3.disableBorderSide(12);
  338. res3.setPaddingBottom(6);
  339. PdfPCell res4 = new PdfPCell(new Phrase(item.getString("参考范围显示效果"), font));
  340. res4.disableBorderSide(4);
  341. res4.setPaddingBottom(6);
  342. table.addCell(res3);
  343. table.addCell(res4);
  344. }
  345. }
  346. PdfPCell sum1 = new PdfPCell(new Phrase("科室小结:", font));
  347. sum1.setHorizontalAlignment(Element.ALIGN_CENTER);
  348. sum1.setVerticalAlignment(Element.ALIGN_CENTER);
  349. sum1.setBackgroundColor(BaseColor.LIGHT_GRAY);
  350. sum1.setPaddingTop(20);
  351. sum1.setPaddingBottom(20);
  352. table.addCell(sum1);
  353. PdfPCell sum2 = new PdfPCell(new Phrase(sumContent, font));
  354. sum2.setColspan(3);
  355. table.addCell(sum2);
  356. if (StringUtil.notBlank(examDoctor)) {
  357. examDoctor = "检查医生:" + examDoctor;
  358. }
  359. if (StringUtil.notBlank(auditDoctor)) {
  360. auditDoctor = "审核医生:" + auditDoctor;
  361. }
  362. PdfPCell doctorCell = new PdfPCell(new Phrase(examDoctor + " " + auditDoctor, font));
  363. doctorCell.setColspan(4);
  364. doctorCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
  365. doctorCell.setPaddingRight(30);
  366. doctorCell.setPaddingTop(10);
  367. doctorCell.disableBorderSide(15);
  368. table.addCell(doctorCell);
  369. table.setSplitLate(false);
  370. document.add(table);
  371. } else {
  372. PdfPTable table = new PdfPTable(8);
  373. table.setWidthPercentage(100);
  374. String[] headers = new String[]{"化验项目", "结果", "单位", "参考值", "化验项目", "结果", "单位", "参考值"};
  375. for (String header : headers) {
  376. PdfPCell headerCell = new PdfPCell(new Phrase(header, font));
  377. headerCell.disableBorderSide(14);
  378. table.addCell(headerCell);
  379. }
  380. for (int i = 0; i < results.size(); i++) {
  381. font = new Font(baseFont, 10, Font.NORMAL);
  382. JSONObject item = results.getJSONObject(i);
  383. String resSign = item.getString("阳性标识");
  384. if (StringUtil.notBlank(resSign)) {
  385. font.setColor(BaseColor.RED);
  386. } else {
  387. font.setColor(BaseColor.BLACK);
  388. }
  389. PdfPCell nameCell = new PdfPCell(new Phrase(item.getString("检查项目"), font));
  390. nameCell.disableBorderSide(15);
  391. table.addCell(nameCell);
  392. PdfPCell resCell = new PdfPCell(new Phrase(item.getString("结果") + resSign, font));
  393. resCell.disableBorderSide(15);
  394. table.addCell(resCell);
  395. PdfPCell unitCell = new PdfPCell(new Phrase(item.getString("单位"), font));
  396. unitCell.disableBorderSide(15);
  397. table.addCell(unitCell);
  398. PdfPCell rangeCell = new PdfPCell(new Phrase(item.getString("参考范围显示效果"), font));
  399. rangeCell.disableBorderSide(i % 2 == 0 ? 7 : 15);
  400. table.addCell(rangeCell);
  401. }
  402. if (StringUtil.notBlank(examDoctor)) {
  403. examDoctor = "检验:" + examDoctor;
  404. }
  405. if (StringUtil.notBlank(auditDoctor)) {
  406. auditDoctor = "审核:" + auditDoctor;
  407. }
  408. font = new Font(baseFont, 12, Font.NORMAL);
  409. font.setColor(BaseColor.BLACK);
  410. PdfPCell doctorCell = new PdfPCell(new Phrase(examDoctor + " " + auditDoctor, font));
  411. doctorCell.setColspan(8);
  412. doctorCell.setHorizontalAlignment(Element.ALIGN_RIGHT);
  413. doctorCell.setPaddingRight(30);
  414. doctorCell.setPaddingTop(10);
  415. doctorCell.disableBorderSide(15);
  416. table.addCell(doctorCell);
  417. PdfPCell tipCell = new PdfPCell(new Phrase("注:此检验报告只对本次标本负责,如有疑问请七日内复查。", font));
  418. tipCell.setColspan(8);
  419. tipCell.setHorizontalAlignment(Element.ALIGN_LEFT);
  420. tipCell.setPaddingTop(10);
  421. tipCell.disableBorderSide(15);
  422. table.addCell(tipCell);
  423. table.setSplitLate(false);
  424. document.add(table);
  425. }
  426. entryIndex += 1;
  427. }
  428. document.newPage();
  429. }
  430. private static Paragraph getTailPageLogo(BaseFont baseFont) throws Exception {
  431. Image logo = Image.getInstance(LOGO_PATH);
  432. logo.scaleAbsolute(240, 110);
  433. Chunk logoChunk = new Chunk(logo, 0, -260, false);
  434. Paragraph paragraph = new Paragraph();
  435. paragraph.setAlignment(Element.ALIGN_CENTER);
  436. paragraph.add(logoChunk);
  437. paragraph.add(Chunk.NEWLINE);
  438. Font font = new Font(baseFont, 30, Font.NORMAL);
  439. Chunk ending = new Chunk("泰和伴您,健康同行!");
  440. ending.setFont(font);
  441. ending.setTextRise(-330);
  442. paragraph.add(ending);
  443. return paragraph;
  444. }
  445. }