package com.yuanchu.mom.service.impl; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.aspose.words.*; import com.aspose.words.Document; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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.deepoove.poi.data.style.Style; import com.deepoove.poi.data.style.TableStyle; import com.deepoove.poi.util.TableTools; import com.itextpdf.text.BadElementException; import com.itextpdf.text.DocumentException; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import com.yuanchu.mom.common.GetLook; import com.yuanchu.mom.common.PrintChina; import com.yuanchu.mom.dto.*; import com.yuanchu.mom.exception.ErrorException; import com.yuanchu.mom.mapper.*; import com.yuanchu.mom.pojo.*; import com.yuanchu.mom.service.InsReportService; import com.yuanchu.mom.service.StandardTemplateService; import com.yuanchu.mom.utils.JackSonUtil; import com.yuanchu.mom.utils.MatrixToImageWriter; import com.yuanchu.mom.utils.QueryWrappers; import com.yuanchu.mom.utils.WordUtils; import com.yuanchu.mom.vo.Result; import org.apache.commons.io.IOUtils; import org.apache.logging.log4j.util.Strings; import org.apache.poi.xwpf.usermodel.*; import org.apache.poi.xwpf.usermodel.ParagraphAlignment; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; /** * @author Administrator * @description 针对表【ins_report(检验报告)】的数据库操作Service实现 * @createDate 2024-03-17 22:10:02 */ @Service public class InsReportServiceImpl extends ServiceImpl implements InsReportService { @Resource private GetLook getLook; @Resource private UserMapper userMapper; @Resource private InsReportMapper insReportMapper; @Autowired ProcessReportMapper1 processReportMapper; @Value("${wordUrl}") private String wordUrl; @Value("${file.path}") private String imgUrl; @Value("${twoCode}") private String twoCode; @Resource private InsOrderMapper insOrderMapper; @Resource private InsOrderStateMapper insOrderStateMapper; @Resource WordUtils wordUtils; @Resource private InsProductMapper insProductMapper; @Resource private InsProductResultMapper insProductResultMapper; @Resource private InsProductResult2Mapper insProductResult2Mapper; @Resource private InsOrderUserMapper insOrderUserMapper; @Resource private InsSampleMapper insSampleMapper; @Resource private InsSampleUserMapper insSampleUserMapper; @Resource private CustomMapper customMapper; @Resource private InsOrderFileMapper insOrderFileMapper; @Resource private StandardTemplateService standardTemplateService; @Override public Map pageInsReport(Page page, ReportPageDto reportPageDto) { Map map = new HashMap<>(); map.put("head", PrintChina.printChina(ReportPageDto.class)); Map map1 = getLook.selectPowerByMethodAndUserId("pageInsReport"); if (map1.get("look") == 1) reportPageDto.setCreateUser(map1.get("userId")); map.put("body", insReportMapper.pageInsReport(page, QueryWrappers.queryWrappers(reportPageDto))); return map; } @Override public int inReport(String url, Integer id) { InsReport insReport = new InsReport(); insReport.setId(id); insReport.setUrlS(url); return insReportMapper.updateById(insReport); } @Override public int upReportUrl(Integer id) { return insReportMapper.update(null, Wrappers.lambdaUpdate().eq(InsReport::getId, id).set(InsReport::getUrlS, null)); } //提交 @Override public int writeReport(Integer id) { InsReport insReport = insReportMapper.selectById(id); insReport.setId(id); insReport.setState(1); insReport.setWriteUserId(getLook.selectPowerByMethodAndUserId(null).get("userId"));//提交人 insReport.setWriteTime(LocalDateTime.now());//提交时间 //获取提交人的签名地址 String signatureUrl; try { signatureUrl = userMapper.selectById(insReport.getWriteUserId()).getSignatureUrl(); } catch (Exception e) { throw new ErrorException("找不到编制人的签名"); } //系统生成报告地址 String url = insReport.getUrl(); //手动上传报告地址 String urlS = insReport.getUrlS(); wordInsertUrl(new HashMap() {{ put("writeUrl", Pictures.ofLocal(imgUrl + "/" + signatureUrl).create()); }}, (urlS == null ? url : urlS).replace("/word", wordUrl)); return insReportMapper.updateById(insReport); } //审核 @Override public int examineReport(Integer id, Integer isExamine, String examineTell) { InsReport insReport = insReportMapper.selectById(id); insReport.setIsExamine(isExamine); if (ObjectUtils.isNotEmpty(examineTell)) { insReport.setExamineTell(examineTell); } insReport.setExamineUserId(getLook.selectPowerByMethodAndUserId(null).get("userId"));//审核人 insReport.setExamineTime(LocalDateTime.now());//审核时间 if (isExamine == 0) { //如果审核不通过 insReport.setState(0);//提交状态改为待提交 return insReportMapper.updateById(insReport); } //获取审核人的签名地址 String signatureUrl; try { signatureUrl = userMapper.selectById(insReport.getExamineUserId()).getSignatureUrl(); } catch (Exception e) { throw new ErrorException("找不到审核人的签名"); } //系统生成报告地址 String url = insReport.getUrl(); //手动上传报告地址 String urlS = insReport.getUrlS(); wordInsertUrl(new HashMap() {{ put("examineUrl", Pictures.ofLocal(imgUrl + "/" + signatureUrl).create()); }}, (urlS == null ? url : urlS).replace("/word", wordUrl)); return insReportMapper.updateById(insReport); } //批准 @Override @Transactional(rollbackFor = Exception.class) public int ratifyReport(Integer id, Integer isRatify, String ratifyTell, String sealUrl) { InsReport insReport = insReportMapper.selectById(id); insReport.setIsRatify(isRatify); if (ObjectUtils.isNotEmpty(ratifyTell)) { insReport.setRatifyTell(ratifyTell); } insReport.setRatifyUserId(getLook.selectPowerByMethodAndUserId(null).get("userId"));//批准人 insReport.setRatifyTime(LocalDateTime.now());//批准时间 if (isRatify == 0) { //如果批准不通过 insReport.setState(0);//提交状态改为待提交 return insReportMapper.updateById(insReport); } insReportMapper.updateById(insReport); //获取批准人的签名地址 String signatureUrl; try { signatureUrl = userMapper.selectById(insReport.getRatifyUserId()).getSignatureUrl(); } catch (Exception e) { throw new ErrorException("找不到批准人的签名"); } //系统生成报告地址 String url = insReport.getUrl(); //手动上传报告地址 String urlS = insReport.getUrlS(); String finalUrl = (urlS == null ? url : urlS).replace("/word", wordUrl); wordInsertUrl(new HashMap() {{ put("ratifyUrl", Pictures.ofLocal(imgUrl + "/" + signatureUrl).create()); put("seal1", Pictures.ofLocal(imgUrl + "/" + sealUrl).create()); put("seal2", Pictures.ofLocal(imgUrl + "/" + sealUrl).create()); }}, finalUrl); wordToPdf(finalUrl, sealUrl); /*新增cnas7.8报告结果*/ ProcessReport processReport = new ProcessReport(); processReport.setInsReportCode(insReport.getCode()); processReportMapper.insert(processReport); return 0; } @Override public int wordInsertUrl(Map map, String url) { XWPFTemplate template = XWPFTemplate.compile(url).render(map); try { template.writeAndClose(Files.newOutputStream(Paths.get(url))); } catch (IOException e) { throw new RuntimeException(e); } return 1; } //报告批量下载 @Override @Transactional(rollbackFor = Exception.class) public String downAll(String ids) { List list = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList()); List insReports = insReportMapper.selectBatchIds(list); String zipFilePath = null; // 临时文件夹路径 try { String tempFolderPath = wordUrl + "/tempFolder"; File tempFolder = new File(tempFolderPath); if (tempFolder.exists()) { deleteDirectory(tempFolder); // 删除旧的临时文件夹 } tempFolder.mkdirs(); // 创建新的临时文件夹 for (InsReport insReport : insReports) { File sourceFile = new File((ObjectUtils.isNotEmpty(insReport.getUrlS()) ? insReport.getUrlS() : insReport.getUrl()).replace("/word", wordUrl)); File destinationFile = new File(tempFolder, sourceFile.getName()); Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } // 压缩临时文件夹 zipFilePath = wordUrl + "/zip/output.zip"; zipDirectory(tempFolderPath, zipFilePath); // 清理临时文件夹 deleteDirectory(tempFolder); System.out.println("ZIP文件创建完成!"); } catch (IOException e) { e.printStackTrace(); } return "/word/zip/output.zip"; } //批量上传 @Override @Transactional(rollbackFor = Exception.class) public int upAll(MultipartFile file) throws IOException { File tempFile = null; File unzipDir = null; try { tempFile = File.createTempFile(wordUrl, ".zip"); file.transferTo(tempFile); unzipDir = new File("uploaded_files"); if (!unzipDir.exists()) { unzipDir.mkdir(); } unzip(tempFile, unzipDir); // 处理解压后的文件 File[] files = unzipDir.listFiles(); if (files != null) { for (File f : files) { // 根据文件名查询id InsReport insReport = insReportMapper.selectOne(Wrappers.lambdaQuery().like(InsReport::getCode, f.getName().replace(".docx", ""))); if (ObjectUtils.isEmpty(insReport)) { throw new ErrorException("没有找到 " + f.getName() + " 这个文件对应的报告数据"); } String urlString; String pathName; try { String path = wordUrl; File realpath = new File(path); if (!realpath.exists()) { realpath.mkdirs(); } pathName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyMMddHHmmss")) + "_" + f.getName(); urlString = realpath + "/" + pathName; // 复制文件到指定路径 Files.copy(f.toPath(), new File(urlString).toPath(), StandardCopyOption.REPLACE_EXISTING); inReport("/word/" + pathName, insReport.getId()); } catch (IOException e) { throw new ErrorException("文件上传失败"); } } } } catch (IOException e) { throw new ErrorException("文件处理失败"); } finally { if (tempFile != null && tempFile.exists()) { tempFile.delete(); } // 递归删除解压目录及其中的文件 if (unzipDir.exists()) { deleteDirectory(unzipDir); // 删除旧的临时文件夹 } } return 0; } //是否需要生成报告: 0不需要;1需要 @Override @Transactional(rollbackFor = Exception.class) public int isReport(InsReportDto insReportDto) { //先判断该订单是否可以去生产报告(是否结束试验) Long count = insOrderStateMapper.selectCount(Wrappers.lambdaQuery() .eq(InsOrderState::getInsOrderId, insReportDto.getId()).eq(InsOrderState::getInsState, 5)); if (count > 0) { if (insReportDto.getState() == 1) { List insReportDto1s = insReportDto.getInsReportDto1s(); for (InsReportDto1 insReportDto1 : insReportDto1s) { if (ObjectUtils.isNotEmpty(insReportDto1.getInsReportDto2s())) { wordUtils.generateReport(insReportDto.getId(), insReportDto1); } } } } else { throw new ErrorException("该订单还未结束试验,无法生成报告!"); } return 0; } //查出该订单下每个站点下的检验次数 @Override public List getInsOrderStateCount(Integer id, Integer sampleId) { List insOrderStateDtos = new ArrayList<>(); InsSample insSample = insSampleMapper.selectById(sampleId); InsOrderStateDto insOrderStateDto = new InsOrderStateDto(); insOrderStateDto.setInsSample(insSample); List insOrderStates = insOrderStateMapper.getInsOrderStateCount(id, insSample.getId()); insOrderStateDto.setInsOrderStates(insOrderStates); insOrderStateDtos.add(insOrderStateDto); return insOrderStateDtos; } //解压文件夹 private void unzip(File zipFile, File destDir) throws IOException { try (ZipFile zip = new ZipFile(zipFile)) { Enumeration entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); File file = new File(destDir, entry.getName()); if (entry.isDirectory()) { file.mkdirs(); } else { file.getParentFile().mkdirs(); try (InputStream in = zip.getInputStream(entry); OutputStream out = new FileOutputStream(file)) { byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } } } } } } // 压缩文件夹 public static void zipDirectory(String sourceDirPath, String zipFilePath) throws IOException { try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFilePath))) { Path sourceDir = Paths.get(sourceDirPath); Files.walk(sourceDir) .filter(path -> !Files.isDirectory(path)) .forEach(path -> { ZipEntry zipEntry = new ZipEntry(sourceDir.relativize(path).toString()); try { zipOut.putNextEntry(zipEntry); Files.copy(path, zipOut); zipOut.closeEntry(); } catch (IOException e) { e.printStackTrace(); } }); } } // 删除文件夹及其内容 public static void deleteDirectory(File directory) throws IOException { if (directory.isDirectory()) { File[] files = directory.listFiles(); if (files != null) { for (File file : files) { deleteDirectory(file); } } } Files.delete(directory.toPath()); } @Override public void wordToPdf(String path, String sealUrl) { CompletableFuture.supplyAsync(() -> { try { wordToPdf(path, path.replace(".docx", ".pdf"), sealUrl); return null; } catch (Exception e) { throw new ErrorException("转换失败"); } }).thenAccept(res -> { }).exceptionally(e -> { e.printStackTrace(); return null; }); } public String wordToPdf(String wordPath, String pdfPath, String sealUrl) { FileOutputStream os = null; try { InputStream is = new ClassPathResource("/lib/license.xml").getInputStream(); License license = new License(); license.setLicense(is); if (!license.getIsLicensed()) { System.out.println("License验证不通过..."); return null; } //生成一个空的PDF文件 File file = new File(pdfPath.replace(".pdf", "-1.pdf")); os = new FileOutputStream(file); //要转换的word文件 com.aspose.words.Document doc = new com.aspose.words.Document(wordPath); doc.save(os, SaveFormat.PDF); //添加骑缝章 stamperCheckMarkPDF(pdfPath.replace(".pdf", "-1.pdf"), pdfPath, imgUrl + "/" + sealUrl); } catch (Exception e) { e.printStackTrace(); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } return null; } /** * 切割图片 * * @param Path 图片路径 * @param n 切割份数 */ public static com.itextpdf.text.Image[] slicingImages(String Path, int n) throws IOException, BadElementException { com.itextpdf.text.Image[] nImage = new com.itextpdf.text.Image[n]; BufferedImage img = ImageIO.read(new File(Path)); int h = img.getHeight(); int w = img.getWidth(); int sw = w / n; for (int i = 0; i < n; i++) { BufferedImage subImg; if (i == n - 1) {//最后剩余部分 subImg = img.getSubimage(i * sw, 0, w - i * sw, h); } else {//前n-1块均匀切 subImg = img.getSubimage(i * sw, 0, sw, h); } ByteArrayOutputStream out = new ByteArrayOutputStream(); ImageIO.write(subImg, Path.substring(Path.lastIndexOf('.') + 1), out); nImage[i] = com.itextpdf.text.Image.getInstance(out.toByteArray()); } return nImage; } /** * 盖骑缝章 * * @param infilePath 原PDF路径 * @param outFilePath 输出PDF路径 */ public static void stamperCheckMarkPDF(String infilePath, String outFilePath, String picPath) throws IOException, DocumentException { PdfReader reader = new PdfReader(infilePath);//选择需要印章的pdf PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(outFilePath));//加完印章后的pdf com.itextpdf.text.Rectangle pageSize = reader.getPageSize(1);//获得第一页 float height = pageSize.getHeight(); float width = pageSize.getWidth(); int nums = reader.getNumberOfPages(); com.itextpdf.text.Image[] nImage = slicingImages(picPath, nums);//生成骑缝章切割图片 for (int n = 1; n <= nums; n++) { PdfContentByte over = stamp.getOverContent(n);//设置在第几页打印印章 com.itextpdf.text.Image img = nImage[n - 1];//选择图片 float newHeight = 100f; float newWidth = img.getWidth() / (img.getHeight() / 100); img.scaleAbsolute(newWidth, newHeight);//控制图片大小 img.setAbsolutePosition(width - newWidth, height / 2 - newHeight / 2);//控制图片位置 over.addImage(img); } stamp.close(); } }