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<TjReportMapper, TjReport> 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<TjReport> 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<TjOrder> 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<TjCustomer> wq1 = new LambdaQueryWrapper<>();
|
wq1.eq(TjCustomer::getCusId, tjOrder.getUserId());
|
TjCustomer tjCustomer = tjCustomerService.getOne(wq1);
|
|
//根据order表的单位id查出单位名称
|
LambdaQueryWrapper<DictComp> wq111 = new LambdaQueryWrapper<>();
|
wq111.eq(DictComp::getDrugManufacturerId, tjOrder.getFirmId());
|
DictComp dictComp = dictCompService.getOne(wq111);
|
|
//查出记录详情 通过order_id
|
LambdaQueryWrapper<TjOrderDetail> wq2 = new LambdaQueryWrapper<>();
|
wq2.eq(TjOrderDetail::getOrderId, tjOrder.getOrderId());
|
List<TjOrderDetail> list = tjOrderDetailService.list(wq2);
|
|
//遍历客户所选的项目(包含子项父项)
|
for (TjOrderDetail tjOrderDetail : list) {
|
//查出单个项目对象 赋值给对象属性
|
TjProject tjProject = projectService.selectTjProjectByProId(tjOrderDetail.getProId());
|
tjOrderDetail.setProject(tjProject);
|
}
|
/*
|
* ====================第一部分 填充体检报告封面模板
|
* */
|
//根据数据库中的模板二进制文件 转pdf 创建文件夹 将pdf放进文件夹
|
LambdaQueryWrapper<TjReportTemplate> 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() + File.separator + userId + "体检报告封面模板.pdf");
|
|
// 模板文件路径
|
String inputFileName = value + File.separator + userId + "体检报告封面模板.pdf";
|
// 生成的文件路径
|
String outputFileName = value + File.separator + 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<String, Object> 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 + File.separator + userId + "体检报告项目详情页.pdf";
|
OutputStream outputStream = Files.newOutputStream(Paths.get(fileName));
|
PdfWriter pdfWriter = PdfWriter.getInstance(document, outputStream);
|
|
// 添加页眉/页脚/水印
|
pdfWriter.setPageEvent((PdfPageEvent) new MyHeaderFooter());// 页眉页脚(需要时设置)
|
|
//打开文档
|
document.open();
|
|
// 获取数据
|
Map<TjOrderRemark, List<TjPdfVO>> tjOrderRemarkObjectMap = addTable(tjNumber);
|
for (Map.Entry<TjOrderRemark, List<TjPdfVO>> entry : tjOrderRemarkObjectMap.entrySet()) {
|
List<TjPdfVO> value = entry.getValue();
|
LambdaQueryWrapper<TjProject> 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 + File.separator + userId + "体检报告封面页.pdf", value + File.separator + userId + "体检报告项目详情页.pdf"};
|
String outputPath1 = value + File.separator;
|
String outputFileName1 = tjNumber + "体检报告.pdf";
|
|
File file1 = new File(outputPath1 + outputFileName1);
|
List<File> 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 + File.separator + userId + "体检报告封面模板.pdf");
|
FileUtil.del(value + File.separator + userId + "体检报告项目详情页.pdf");
|
FileUtil.del(value + File.separator + userId + "体检报告封面页.pdf");
|
|
//修改order表中的打印报告时间为当前时间
|
LambdaUpdateWrapper<TjOrder> 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<TjReport> queryWrapper) {
|
return tjReportMapper.selectCount(queryWrapper);
|
}
|
|
|
public Map<TjOrderRemark, List<TjPdfVO>> addTable(String tjNumber) {
|
//创建map 键为父项目 值为子项目集合
|
Map<TjOrderRemark, List<TjPdfVO>> printReport = new HashMap<>();
|
|
//通过传入的体检号查到该客户的体检记录
|
LambdaQueryWrapper<TjOrder> wq1 = new LambdaQueryWrapper<>();
|
wq1.eq(TjOrder::getTjNumber, tjNumber);
|
TjOrder one = tjOrderService.getOne(wq1);
|
|
|
//拿到体检记录的orderid,查出项目详细信息
|
LambdaQueryWrapper<TjOrderDetail> wq = new LambdaQueryWrapper<>();
|
wq.eq(TjOrderDetail::getOrderId, one.getOrderId());
|
List<TjOrderDetail> tjOrderDetails = tjOrderDetailService.list(wq);
|
|
//遍历体检记录 将项目的具体信息
|
//遍历客户所选的项目(包含子项父项)
|
for (TjOrderDetail tjOrderDetail : tjOrderDetails) {
|
//查出单个项目对象 赋值给对象属性
|
TjProject tjProject = projectService.selectTjProjectByProId(tjOrderDetail.getProId());
|
tjOrderDetail.setProject(tjProject);
|
}
|
|
//查出客户个人信息
|
LambdaQueryWrapper<TjCustomer> wq22 = new LambdaQueryWrapper<>();
|
wq22.eq(TjCustomer::getCusId, one.getUserId());
|
TjCustomer customer = tjCustomerService.getOne(wq22);
|
|
|
//查询夫项目备注表
|
LambdaQueryWrapper<TjOrderRemark> wqq = new LambdaQueryWrapper<>();
|
wqq.eq(TjOrderRemark::getTjNumber, tjNumber);
|
List<TjOrderRemark> tjOrderRemarks = tjOrderRemarkService.list(wqq);
|
|
for (TjOrderRemark tjOrderRemark : tjOrderRemarks) {
|
printReport.put(tjOrderRemark, null);
|
}
|
|
|
for (Map.Entry<TjOrderRemark, List<TjPdfVO>> entry : printReport.entrySet()) {
|
List<TjPdfVO> tjPdfVOS = new ArrayList<>();
|
for (TjOrderDetail tjOrderDetail : tjOrderDetails) {
|
if (tjOrderDetail.getProject().getProParentId().equals(entry.getKey().getProId())) {
|
//查标准
|
LambdaQueryWrapper<TjStandard> wq6 = new LambdaQueryWrapper<>();
|
wq6.eq(TjStandard::getProId, tjOrderDetail.getProId());
|
List<TjStandard> 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<TjStandard> 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<TjPdfVO> 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<String> tjNumbers) {
|
return sqlGetReportToMake(tjNumbers);
|
|
}
|
|
/**
|
* 通过sql 直接查报告base64进行整合返回
|
* 如果sql数据量巨大 查询缓慢 可以试试 makeReport(List<String > tjNumbers)已注释
|
* @param tjNumbers
|
* @return
|
*/
|
private AjaxResult sqlGetReportToMake(List<String> tjNumbers) {
|
LambdaQueryWrapper<TjReport> tjReportLambdaQueryWrapper = new LambdaQueryWrapper<>();
|
tjReportLambdaQueryWrapper.in(TjReport::getTjNumber, tjNumbers);
|
List<TjReport> list = tjReportService.list(tjReportLambdaQueryWrapper);
|
ArrayList<String> base64Pdfs = new ArrayList<>();
|
for (TjReport report : list) {
|
if (report == null || report.getReport() == null) {
|
// 没有该报告 直接跳过
|
continue;
|
}
|
base64Pdfs.add(report.getReport());
|
}
|
tjNumbers.forEach(tjNumber ->{
|
LambdaUpdateWrapper<TjOrder> 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("批量生成失败");
|
}
|
}
|
}
|