package com.ruoyi.process.service.impl; import cn.hutool.core.lang.UUID; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.config.ConfigureBuilder; import com.deepoove.poi.data.*; import com.deepoove.poi.data.style.*; import com.ruoyi.common.core.domain.entity.User; import com.ruoyi.common.utils.QueryWrappers; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SignatureImageUtil; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.ruoyi.framework.exception.ErrorException; import com.ruoyi.inspect.mapper.InsOrderMapper; import com.ruoyi.inspect.mapper.InsReportMapper; import com.ruoyi.inspect.pojo.InsOrder; import com.ruoyi.inspect.pojo.InsReport; import com.ruoyi.inspect.util.HackLoopTableRenderPolicy; import com.ruoyi.process.dto.ProcessReportDto; import com.ruoyi.process.mapper.ProcessReportMapper; import com.ruoyi.process.pojo.ProcessReport; import com.ruoyi.process.service.ProcessReportService; import com.ruoyi.system.mapper.UserMapper; import org.apache.commons.io.IOUtils; import org.apache.poi.xwpf.usermodel.*; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; /** *

* 检验报告发放登记表 服务实现类 *

* * @author * @since 2024-11-05 08:58:39 */ @Service @Transactional(rollbackFor = Exception.class) public class ProcessReportServiceImpl extends ServiceImpl implements ProcessReportService { @Resource private ProcessReportMapper processReportMapper; @Value("${file.path}") private String imgUrl; @Value("${wordUrl}") private String wordUrl; @Resource private UserMapper userMapper; @Resource private InsReportMapper insReportMapper; @Resource private InsOrderMapper insOrderMapper; @Override public IPage pageProcessReport(Page page, ProcessReportDto processReport) { // #21 打开列表时,自动带出已通过审批(批准状态=批准)但尚未登记的检验单 autoBringOutApproved(); IPage processReportIPage = processReportMapper.pageProcessReport(page, QueryWrappers.queryWrappers(processReport)); return processReportIPage; } /** * 扫描已批准但尚未进入报告结果登记表的检验报告,自动生成待登记记录(以报告编号去重,幂等)。 */ private void autoBringOutApproved() { List approved = insReportMapper.selectList(Wrappers.lambdaQuery() .eq(InsReport::getIsRatify, 1) .eq(InsReport::getIsPass, 1)); if (approved.isEmpty()) { return; } Set existing = this.list(Wrappers.lambdaQuery() .select(ProcessReport::getInsReportCode)).stream() .map(ProcessReport::getInsReportCode) .filter(StringUtils::isNotBlank) .collect(Collectors.toCollection(HashSet::new)); for (InsReport report : approved) { String code = report.getCode(); if (StringUtils.isBlank(code) || existing.contains(code)) { continue; } ProcessReport pr = new ProcessReport(); pr.setInsReportCode(code); pr.setInspectionOrderId(report.getInsOrderId()); if (report.getRatifyTime() != null) { pr.setSendTime(report.getRatifyTime().toLocalDate()); } if (report.getInsOrderId() != null) { InsOrder order = insOrderMapper.selectById(report.getInsOrderId()); if (order != null) { pr.setSend(order.getCompany()); pr.setMethod(getReportDeliveryName(order)); } } this.save(pr); existing.add(code); } } private String getReportDeliveryName(InsOrder order) { if (order.getReportDelivery() != null) { switch (order.getReportDelivery()) { case 1: return "自取"; case 2: return "快递"; case 3: return "电子传送"; default: break; } } // 兼容尚未维护 report_delivery 的历史委托单。 return order.getSend() != null && order.getSend() == 1 ? "自取" : "其他"; } @Override public void downloadStampedReport(Integer id, String format, HttpServletResponse response) { if (id == null) { throw new ErrorException("报告结果不能为空"); } ProcessReport processReport = getById(id); if (processReport == null) { throw new ErrorException("报告结果不存在"); } if (StringUtils.isBlank(processReport.getInsReportCode()) && processReport.getInspectionOrderId() == null) { throw new ErrorException("该记录未关联检验报告,无法下载"); } String downloadFormat = StringUtils.isBlank(format) ? "pdf" : format.trim().toLowerCase(); if (!"pdf".equals(downloadFormat) && !"word".equals(downloadFormat)) { throw new ErrorException("下载格式不正确"); } com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper query = Wrappers.lambdaQuery() .eq(InsReport::getIsRatify, 1) .eq(StringUtils.isNotBlank(processReport.getInsReportCode()), InsReport::getCode, processReport.getInsReportCode()) .eq(processReport.getInspectionOrderId() != null, InsReport::getInsOrderId, processReport.getInspectionOrderId()) .orderByDesc(InsReport::getId) .last("limit 1"); InsReport report = insReportMapper.selectOne(query); if (report == null) { throw new ErrorException("未找到已批准的报告,无法下载有章报告"); } String fileUrl; String extension; String contentType; if ("word".equals(downloadFormat)) { fileUrl = StringUtils.isNotBlank(report.getUrlS()) ? report.getUrlS() : report.getUrl(); extension = ".docx"; contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; } else { fileUrl = report.getTempUrlPdf(); extension = ".pdf"; contentType = "application/pdf"; } if ("pdf".equals(downloadFormat) && StringUtils.isBlank(fileUrl)) { String reportUrl = StringUtils.isNotBlank(report.getUrlS()) ? report.getUrlS() : report.getUrl(); if (StringUtils.isNotBlank(reportUrl) && reportUrl.toLowerCase().endsWith(".docx")) { fileUrl = reportUrl.substring(0, reportUrl.length() - 5) + ".pdf"; } } if (StringUtils.isBlank(fileUrl) || !fileUrl.replace('\\', '/').startsWith("/word/")) { throw new ErrorException("有章报告尚未生成,请先完成报告批准"); } Path root = Paths.get(wordUrl).toAbsolutePath().normalize(); Path file = root.resolve(fileUrl.replace('\\', '/').substring("/word/".length())).normalize(); if (!file.startsWith(root) || !Files.isRegularFile(file)) { throw new ErrorException("有章报告文件不存在,请重新批准生成"); } try { String filename = StringUtils.isNotBlank(processReport.getInsReportCode()) ? processReport.getInsReportCode() + extension : file.getFileName().toString(); String encodedName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20"); response.setContentType(contentType); response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); response.setHeader("download-filename", encodedName); response.setContentLengthLong(Files.size(file)); try (InputStream inputStream = Files.newInputStream(file); OutputStream outputStream = response.getOutputStream()) { IOUtils.copy(inputStream, outputStream); outputStream.flush(); } } catch (IOException e) { throw new ErrorException("有章报告下载失败"); } } @Override public void exportProcessReport(ProcessReportDto dto, HttpServletResponse response) { List processReports = processReportMapper.exportProcessReport(); for (ProcessReportDto processReport : processReports) { // 发送人生成签名图片 processReport.setSendUserRender(StringUtils.isNotBlank(processReport.getSendUserUrl()) ? Pictures.ofLocal(imgUrl + "/" + processReport.getSendUserUrl()).create() : null); // 签收人生成图片 processReport.setSignatoryRender(StringUtils.isNotBlank(processReport.getSignatory()) ? Pictures.ofStream(SignatureImageUtil.saveImageToFile(processReport.getSignatory())).create() : null); } // 获取路径 InputStream inputStream = this.getClass().getResourceAsStream("/static/report-deal.docx"); Configure configure = Configure.builder() .bind("reportList", new HackLoopTableRenderPolicy()) .build(); XWPFTemplate template = XWPFTemplate.compile(inputStream, configure).render( new HashMap() {{ put("reportList", processReports); }}); try { response.setContentType("application/msword"); String fileName = URLEncoder.encode( "检验报告发放登记表", "UTF-8"); response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".docx"); OutputStream os = response.getOutputStream(); template.write(os); os.flush(); os.close(); inputStream.close(); inputStream.close(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("导出失败"); } } }