package com.ltkj.hosp.service.impl; import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; import java.util.List; import java.util.stream.Collectors; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itextpdf.text.*; import com.itextpdf.text.pdf.*; import com.itextpdf.text.pdf.draw.LineSeparator; import com.ltkj.common.core.domain.AjaxResult; import com.ltkj.common.core.domain.entity.SysDictData; import com.ltkj.common.utils.DateUtils; import com.ltkj.common.utils.PDFDocumentUtil; import com.ltkj.common.utils.SecurityUtils; import com.ltkj.common.utils.pdfutils.MergePdf; import com.ltkj.common.utils.pdfutils.MyHeaderFooter; import com.ltkj.common.utils.pdfutils.PDFBinaryUtil; import com.ltkj.common.utils.pdfutils.PdfUtils; import com.ltkj.hosp.domain.*; import com.ltkj.hosp.service.*; import com.ltkj.mall.mallOrderUtils.TjConstants; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.ltkj.hosp.mapper.TjReportMapper; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.Resource; import static com.ltkj.common.utils.pdfutils.PDFBinaryUtil.getPDFBinary; /** * 体检报告存储Service业务层处理 * * @author ltkj * @date 2022-12-06 */ @Service public class TjReportServiceImpl extends ServiceImpl implements ITjReportService { @Resource private TjReportMapper tjReportMapper; @Autowired private ITjReportService tjReportService; @Resource private ITjCustomerService tjCustomerService; @Autowired private ITjOrderService tjOrderService; @Autowired private ITjOrderDetailService tjOrderDetailService; @Resource private ITjProjectService projectService; @Resource private IDictCompService dictCompService; @Resource private ITjReportTemplateService reportTemplateService; @Resource private ITjOrderRemarkService tjOrderRemarkService; @Resource private ITjStandardService tjStandardService; /** * 查询体检报告存储 * * @param reId 体检报告存储主键 * @return 体检报告存储 */ @Override public TjReport selectTjReportByReId(Long reId) { return tjReportMapper.selectTjReportByReId(reId); } /** * 查询体检报告存储列表 * * @param tjReport 体检报告存储 * @return 体检报告存储 */ @Override public List selectTjReportList(TjReport tjReport) { return tjReportMapper.selectTjReportList(tjReport); } /** * 新增体检报告存储 * * @param tjReport 体检报告存储 * @return 结果 */ @Override public int insertTjReport(TjReport tjReport) { return tjReportMapper.insertTjReport(tjReport); } /** * 修改体检报告存储 * * @param tjReport 体检报告存储 * @return 结果 */ @Override public int updateTjReport(TjReport tjReport) { return tjReportMapper.updateTjReport(tjReport); } /** * 批量删除体检报告存储 * * @param reIds 需要删除的体检报告存储主键 * @return 结果 */ @Override public int deleteTjReportByReIds(Long[] reIds) { return tjReportMapper.deleteTjReportByReIds(reIds); } /** * 删除体检报告存储信息 * * @param reId 体检报告存储主键 * @return 结果 */ @Override public int deleteTjReportByReId(Long reId) { return tjReportMapper.deleteTjReportByReId(reId); } @Value("${path.filePath}") private String value; @Override public AjaxResult getTjReport(String tjNumber) { //根据体检号 //在order里查询体检状态 判断体检是否完成 LambdaQueryWrapper wq = new LambdaQueryWrapper<>(); wq.eq(TjOrder::getTjNumber, tjNumber); TjOrder tjOrder = tjOrderService.getOne(wq); if (null != tjOrder) { Integer checkStatus = tjOrder.getCheckStatus(); if (checkStatus == 1) { //查出客户个人信息 通过user_id LambdaQueryWrapper wq1 = new LambdaQueryWrapper<>(); wq1.eq(TjCustomer::getCusId, tjOrder.getUserId()); TjCustomer tjCustomer = tjCustomerService.getOne(wq1); //根据order表的单位id查出单位名称 LambdaQueryWrapper wq111 = new LambdaQueryWrapper<>(); wq111.eq(DictComp::getDrugManufacturerId, tjOrder.getFirmId()); DictComp dictComp = dictCompService.getOne(wq111); //查出记录详情 通过order_id LambdaQueryWrapper wq2 = new LambdaQueryWrapper<>(); wq2.eq(TjOrderDetail::getOrderId, tjOrder.getOrderId()); List list = tjOrderDetailService.list(wq2); //遍历客户所选的项目(包含子项父项) for (TjOrderDetail tjOrderDetail : list) { //查出单个项目对象 赋值给对象属性 TjProject tjProject = projectService.selectTjProjectByProId(tjOrderDetail.getProId()); tjOrderDetail.setProject(tjProject); } /* * ====================第一部分 填充体检报告封面模板 * */ //根据数据库中的模板二进制文件 转pdf 创建文件夹 将pdf放进文件夹 LambdaQueryWrapper tjReportTemplateLambdaQueryWrapper = new LambdaQueryWrapper<>(); tjReportTemplateLambdaQueryWrapper.eq(TjReportTemplate::getFlag, 1); TjReportTemplate one1 = reportTemplateService.getOne(tjReportTemplateLambdaQueryWrapper); String template = one1.getTemplate(); //拿到二进制 //本地创建临时文件夹 //String userId ="10000"; //当前登录的人工号 String userId = SecurityUtils.getLoginUser().getUsername(); //二进制转pdf 存储在临时文件夹中 PDFBinaryUtil.base64StringToPDF(template, FileUtil.mkdir(value).getPath() + "\\" + userId + "体检报告封面模板.pdf"); // 模板文件路径 String inputFileName = value + "\\" + userId + "体检报告封面模板.pdf"; // 生成的文件路径 String outputFileName = value + "\\" + userId + "体检报告封面页.pdf"; OutputStream os = null; PdfStamper ps = null; PdfReader reader = null; File file = new File(outputFileName); try { os = Files.newOutputStream(file.toPath()); // 读入pdf表单 reader = new PdfReader(inputFileName); // 根据表单生成一个新的pdf ps = new PdfStamper(reader, os); // 获取pdf表单 AcroFields form = ps.getAcroFields(); // 给表单添加中文字体 //String prefixFont = "C:Windows\\Fonts" + File.separator + "STFANGSO.TTF"; //该字体造成类型不均匀,但是pdf转图片不乱码 //BaseFont bf = BaseFont.createFont("C:Windows\\Fonts\\simfang.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); form.addSubstitutionFont(bf); // 填充数据给表格 Map data = new HashMap<>(); data.put("name", tjCustomer.getCusName()); //填充性别:判断男女 Long cusSex = tjCustomer.getCusSex(); String sex; if (cusSex == 0) { sex = "男"; } else { sex = "女"; } data.put("sex", sex); data.put("age", DateUtil.ageOfNow(tjCustomer.getCusBrithday())); data.put("tjnumber", tjNumber); data.put("tjdate", DateUtils.parseDateToStr("yyyy/MM/dd", tjOrder.getCreateTime())); data.put("phone", tjCustomer.getCusPhone()); if (dictComp == null) { data.put("work", "无"); } else { data.put("work", dictComp.getCnName()); } data.put("remark", "示例:身高体重" + "\n1、合理控制饮食,少吃点" + "\n心电图" + "\n请注意保持!!!这里放建议/异常啥的。。。。或总检建议" + tjOrder.getCheckAdvice()); // 遍历data 给pdf表单表格赋值 for (String key : data.keySet()) { form.setField(key, data.get(key).toString()); } //设置为无法编辑 ps.setFormFlattening(true); ps.close(); os.close(); reader.close(); /* * ==========================第二部分 生成项目详情 */ //文档对象 实现A4纸页面 Document document = new Document(PageSize.A4); //document.setMarginMirroring(true); //设置文档的页边距就是距离页面边上的距离,分别为:左边距,右边距,上边距,下边距 document.setMargins(70, 70, 40, 40); //这个是生成pdf的位置以及名称 String fileName = value + "\\" + userId + "体检报告项目详情页.pdf"; OutputStream outputStream = Files.newOutputStream(Paths.get(fileName)); PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream); // 添加页眉/页脚/水印 pdfWriter.setPageEvent((PdfPageEvent) new MyHeaderFooter());// 页眉页脚(需要时设置) //打开文档 document.open(); // 获取数据 Map> tjOrderRemarkObjectMap = addTable(tjNumber); for (Map.Entry> entry : tjOrderRemarkObjectMap.entrySet()) { List value = entry.getValue(); LambdaQueryWrapper wqqq = new LambdaQueryWrapper<>(); wqqq.eq(TjProject::getProId, entry.getKey().getProId()); TjProject one11 = projectService.getOne(wqqq); String titleName = one11.getProName(); // 设置标题字体样式 Font titleFonts = PdfUtils.setFont(9); Paragraph paragraph = PdfUtils.setParagraph(titleFonts, titleName); // 设置表格 // 定义列名 String[] titles = {"体检项目", "体检结果", "单位", "参考范围"}; // 获取列表数据 //设置表头字体样式 Font headFont = PdfUtils.setFont(9); // 设置正文字体样式:12号 Font textFont = PdfUtils.setFont(9); //创建表格 将表头字体和正文字体放进去 PdfPTable table = setTable(headFont, textFont, titles, value); // 填充表格内容 document.add(paragraph); document.add(table); //判断备注是否为空 空不能显示null if (entry.getKey().getRemark() == null) { entry.getKey().setRemark(""); } //备注 String remark = "备注:" + entry.getKey().getRemark(); Font remarkFonts = PdfUtils.setFont(9); Paragraph pp = PdfUtils.setParagraph(remarkFonts, remark); document.add(pp); //主检医师 String doctorName = "主检医师:" + entry.getKey().getDoctorName(); Font doctorFonts = PdfUtils.setFont(9); Paragraph df = PdfUtils.setParagraph(doctorFonts, doctorName); df.setAlignment(Element.ALIGN_RIGHT); document.add(df); //分割线 LineSeparator objectName = new LineSeparator(); document.add(objectName); } /* * document关闭的其实是文件的监听状态,writer关闭的是io流,writer创建在document之后 * */ document.close(); pdfWriter.close(); outputStream.close(); //=============================== 第三部分 合并体检报告封面页和体检报告项目详情页 String[] files1 = {value + "\\" + userId + "体检报告封面页.pdf", value + "\\" + userId + "体检报告项目详情页.pdf"}; String outputPath1 = value + "\\"; String outputFileName1 = tjNumber + "体检报告.pdf"; File file1 = new File(outputPath1 + outputFileName1); List f = new ArrayList<>(); for (String s : files1) { f.add(new File(s)); } MergePdf.mergeFileToPDF(f, file1); //============================= 第四部分 将pdf路径存储数据库 文件转二进制存储和和路径存储 TjReport tjReport = new TjReport(); tjReport.setTjNumber(String.valueOf(tjNumber)); tjReport.setPath(outputPath1 + outputFileName1); String pdfBinary = getPDFBinary(outputPath1 + outputFileName1); tjReport.setReport(pdfBinary); tjReportService.save(tjReport); //将临时文件夹中的四个文件删除 //FileUtil.del(value+"\\"+tjNumber + "体检报告.pdf"); FileUtil.del(value + "\\" + userId + "体检报告封面模板.pdf"); FileUtil.del(value + "\\" + userId + "体检报告项目详情页.pdf"); FileUtil.del(value + "\\" + userId + "体检报告封面页.pdf"); //修改order表中的打印报告时间为当前时间 LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(TjOrder::getTjNumber, tjNumber); updateWrapper.set(TjOrder::getReportTime, new Date()); tjOrderService.update(updateWrapper); return AjaxResult.success("已生成报告!可直接点击预览!"); } catch (Exception e) { e.printStackTrace(); return AjaxResult.error("PDF导出失败"); } } } return null; } @Override public Integer getSelectCount(Wrapper queryWrapper) { return tjReportMapper.selectCount(queryWrapper); } public Map> addTable(String tjNumber) { //创建map 键为父项目 值为子项目集合 Map> printReport = new HashMap<>(); //通过传入的体检号查到该客户的体检记录 LambdaQueryWrapper wq1 = new LambdaQueryWrapper<>(); wq1.eq(TjOrder::getTjNumber, tjNumber); TjOrder one = tjOrderService.getOne(wq1); //拿到体检记录的orderid,查出项目详细信息 LambdaQueryWrapper wq = new LambdaQueryWrapper<>(); wq.eq(TjOrderDetail::getOrderId, one.getOrderId()); List tjOrderDetails = tjOrderDetailService.list(wq); //遍历体检记录 将项目的具体信息 //遍历客户所选的项目(包含子项父项) for (TjOrderDetail tjOrderDetail : tjOrderDetails) { //查出单个项目对象 赋值给对象属性 TjProject tjProject = projectService.selectTjProjectByProId(tjOrderDetail.getProId()); tjOrderDetail.setProject(tjProject); } //查出客户个人信息 LambdaQueryWrapper wq22 = new LambdaQueryWrapper<>(); wq22.eq(TjCustomer::getCusId, one.getUserId()); TjCustomer customer = tjCustomerService.getOne(wq22); //查询夫项目备注表 LambdaQueryWrapper wqq = new LambdaQueryWrapper<>(); wqq.eq(TjOrderRemark::getTjNumber, tjNumber); List tjOrderRemarks = tjOrderRemarkService.list(wqq); for (TjOrderRemark tjOrderRemark : tjOrderRemarks) { printReport.put(tjOrderRemark, null); } for (Map.Entry> entry : printReport.entrySet()) { List tjPdfVOS = new ArrayList<>(); for (TjOrderDetail tjOrderDetail : tjOrderDetails) { if (tjOrderDetail.getProject().getProParentId().equals(entry.getKey().getProId())) { //查标准 LambdaQueryWrapper wq6 = new LambdaQueryWrapper<>(); wq6.eq(TjStandard::getProId, tjOrderDetail.getProId()); List list2 = tjStandardService.list(wq6); //判断标准个数,根据年龄性别 推断出一个标准 if (list2.size() == 0) { tjOrderDetail.setStandard(null); } else if (list2.size() == 1) { //查出一条标准 不区分年龄性别 tjOrderDetail.setStandard(list2.get(0)); } else { //多条标准 根据客户年龄性别判断 //性别 Long cusSex = customer.getCusSex(); Date cusBrithday = customer.getCusBrithday(); //年龄 int age = DateUtil.ageOfNow(cusBrithday); //遍历判断标准 for (TjStandard tjStandard : list2) { LambdaQueryWrapper wq8 = new LambdaQueryWrapper<>(); //判断性别 if (tjStandard.getTjSex() != null) { wq8.eq(TjStandard::getTjSex, cusSex); } //判断年龄段 if (tjStandard.getTjType() != null) { wq8.eq(TjStandard::getTjType, getAgeType(age)); } TjStandard standard = tjStandardService.getOne(wq8); tjOrderDetail.setStandard(standard); } } TjPdfVO tjPdfVO = new TjPdfVO(); tjPdfVO.setProName(tjOrderDetail.getProject().getProName()); //体检项目名 tjPdfVO.setProResult(tjOrderDetail.getProResult()); //体检结果 tjPdfVO.setCompany(tjOrderDetail.getStandard().getCompany()); //单位 String tjStandardGtValue = tjOrderDetail.getStandard().getTjStandardGtValue(); String tjStandardLtValue = tjOrderDetail.getStandard().getTjStandardLtValue(); tjPdfVO.setStandardValue(tjStandardLtValue + "-" + tjStandardGtValue); //参考值范围 //满足条件的子项目加入集合 tjPdfVOS.add(tjPdfVO); } } printReport.put(entry.getKey(), tjPdfVOS); } return printReport; } public int getAgeType(Integer age) { int type = 0; if (1 < age && age < 4) { type = 1; } else if (5 < age && age < 11) { type = 2; } else if (12 < age && age < 18) { type = 3; } else if (19 < age && age < 35) { type = 4; } else if (36 < age && age < 59) { type = 5; } else if (60 < age && age < 150) { type = 6; } return type; } /** * 设置 * 表格内容 * * @param headFont * @param textFont * @param title * @param list * @return */ public static PdfPTable setTable(Font headFont, Font textFont, String[] title, List list) { //四列 PdfPTable table = PdfUtils.createTable(new float[]{120, 120, 120, 120}); //画标题 for (String head : title) { table.addCell(PdfUtils.createCell(head, headFont)); } //画内容 for (TjPdfVO tjPdfVO : list) { table.addCell(PdfUtils.createCell(tjPdfVO.getProName(), textFont)); table.addCell(PdfUtils.createCell(tjPdfVO.getProResult(), textFont)); table.addCell(PdfUtils.createCell(tjPdfVO.getCompany(), textFont)); table.addCell(PdfUtils.createCell(tjPdfVO.getStandardValue(), textFont)); } return table; } @Override public AjaxResult makeBatchReport(List tjNumbers) { return sqlGetReportToMake(tjNumbers); } /** * 通过sql 直接查报告base64进行整合返回 * 如果sql数据量巨大 查询缓慢 可以试试 makeReport(List tjNumbers)已注释 * @param tjNumbers * @return */ private AjaxResult sqlGetReportToMake(List tjNumbers) { LambdaQueryWrapper tjReportLambdaQueryWrapper = new LambdaQueryWrapper<>(); tjReportLambdaQueryWrapper.in(TjReport::getTjNumber, tjNumbers); List list = tjReportService.list(tjReportLambdaQueryWrapper); ArrayList base64Pdfs = new ArrayList<>(); for (TjReport report : list) { if (report == null || report.getReport() == null) { // 没有该报告 直接跳过 continue; } base64Pdfs.add(report.getReport()); } tjNumbers.forEach(tjNumber ->{ LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper<>(); updateWrapper.eq(TjOrder::getTjNumber, tjNumber); updateWrapper.set(TjOrder::getPrintLastTime, new Date()); updateWrapper.set(TjOrder::getDownloadLastTime, new Date()); updateWrapper.set(TjOrder::getStatus, TjConstants.TJ_END); tjOrderService.update(updateWrapper); }); try { byte[] mergePDF = PDFDocumentUtil.mergePDFs(base64Pdfs); String s = Base64.getEncoder().encodeToString(mergePDF); return AjaxResult.success().put("file",s); // 本地生成测试 // String PDF_FILE = "d:\\Users\\w\\Desktop\\test.pdf"; // BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(PDF_FILE)); // outputStream.write(mergePDF); // outputStream.flush(); // outputStream.close(); } catch (DocumentException | IOException e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return AjaxResult.error("批量生成失败"); } } }