zss
2024-09-10 22d3a8dc4185c5461bee9e42a9f4a2775ff448e6
inspect-server/src/main/java/com/yuanchu/mom/service/impl/InsReportServiceImpl.java
@@ -1,43 +1,83 @@
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.spire.doc.Document;
import com.spire.doc.FileFormat;
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.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.InsOrderPlanDTO;
import com.yuanchu.mom.dto.ReportPageDto;
import com.yuanchu.mom.dto.SampleOrderDto;
import com.yuanchu.mom.dto.SampleProductDto;
import com.yuanchu.mom.exception.ErrorException;
import com.yuanchu.mom.pojo.InsReport;
import com.yuanchu.mom.mapper.*;
import com.yuanchu.mom.pojo.*;
import com.yuanchu.mom.service.InsReportService;
import com.yuanchu.mom.mapper.InsReportMapper;
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 lombok.AllArgsConstructor;
import com.yuanchu.mom.vo.Result;
import org.apache.commons.io.IOUtils;
import org.apache.poi.xwpf.usermodel.*;
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 java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
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
*/
 * @author Administrator
 * @description 针对表【ins_report(检验报告)】的数据库操作Service实现
 * @createDate 2024-03-17 22:10:02
 */
@Service
public class InsReportServiceImpl extends ServiceImpl<InsReportMapper, InsReport>
    implements InsReportService{
        implements InsReportService {
    @Resource
    private GetLook getLook;
    @Resource
    private UserMapper userMapper;
    @Resource
    private InsReportMapper insReportMapper;
@@ -45,26 +85,56 @@
    @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
    private InsProductMapper insProductMapper;
    @Resource
    private InsSampleMapper insSampleMapper;
    @Resource
    private InsSampleUserMapper insSampleUserMapper;
    @Resource
    private CustomMapper customMapper;
    @Resource
    private InsOrderFileMapper insOrderFileMapper;
    @Resource
    private StandardTemplateService standardTemplateService;
    @Override
    public Map<String, Object> pageInsReport(Page page, ReportPageDto reportPageDto) {
        Map<String, Object> map = new HashMap<>();
        map.put("head", PrintChina.printChina(ReportPageDto.class));
        Map<String, Integer> 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 String wordToHtml(String path) {
        try(ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            Document document = new Document();
            document.loadFromFile(path.replace("/word", wordUrl));
            document.saveToFile(outputStream, FileFormat.Html);
            return outputStream.toString();
        } catch (Exception e) {
            throw new ErrorException("转换失败");
        User user = userMapper.selectById(map1.get("userId"));//当前登录的人
        //获取当前人所属实验室id
        String departLimsId = user.getDepartLimsId();
        String laboratory = null;
        if (ObjectUtils.isNotEmpty(departLimsId) && !departLimsId.equals("")) {
            String[] split = departLimsId.split(",");
            //查询对应架构名称(通信实验室,电力实验室,检测办)
            String departLims = insOrderMapper.seldepLimsId(Integer.parseInt(split[split.length - 1]));
            if (departLims.contains("实验室")) {
                laboratory = departLims;
            }
        }
        map.put("body", insReportMapper.pageInsReport(page, QueryWrappers.queryWrappers(reportPageDto), laboratory));
        return map;
    }
    @Override
@@ -79,8 +149,800 @@
    public int upReportUrl(Integer id) {
        return insReportMapper.update(null, Wrappers.<InsReport>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<String, Object>() {{
            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<String, Object>() {{
            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);
        }
        //获取批准人的签名地址
        String signatureUrl;
        try {
            signatureUrl = userMapper.selectById(insReport.getRatifyUserId()).getSignatureUrl();
        } catch (Exception e) {
            throw new ErrorException("找不到批准人的签名");
        }
        //获取场所的报告专用章
       /* String sealUrl;
        try {
            String laboratory = insOrderMapper.selectById(insReport.getInsOrderId()).getLaboratory();
            sealUrl = insReportMapper.getLaboratoryByName(laboratory);
        } catch (Exception e) {
            throw new ErrorException("找不到报告专用章");
        }
        if (sealUrl == null) throw new ErrorException("找不到报告专用章");*/
        //系统生成报告地址
        String url = insReport.getUrl();
        //手动上传报告地址
        String urlS = insReport.getUrlS();
        String finalUrl = (urlS == null ? url : urlS).replace("/word", wordUrl);
        wordInsertUrl(new HashMap<String, Object>() {{
            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);
        InsOrder insOrder = new InsOrder();
        insOrder.setId(insReportMapper.selectById(id).getInsOrderId());
        insOrder.setState(4);
        insOrderMapper.updateById(insOrder);
        return insReportMapper.updateById(insReport);
    }
    @Override
    public int wordInsertUrl(Map<String, Object> 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<Long> list = Arrays.stream(ids.split(",")).map(Long::parseLong).collect(Collectors.toList());
        List<InsReport> 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
                    String name = f.getName();
                    InsReport insReport = insReportMapper.selectOne(Wrappers.<InsReport>lambdaQuery().like(InsReport::getCode, f.getName().replace(".docx", "").replace("JCZX", "JCZX/")));
                    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(Integer id, Integer state) {
        //先判断该订单是否可以去生产报告
        Long count = insOrderStateMapper.selectCount(Wrappers.<InsOrderState>lambdaQuery().eq(InsOrderState::getInsOrderId, id).eq(InsOrderState::getInsState, 5));
        if (count > 0) {
            if (state == 1) {
                generateReport(id);
            } else {
                //结束订单
                InsOrder insOrder = new InsOrder();
                insOrder.setId(id);
                insOrder.setState(4);
                insOrderMapper.updateById(insOrder);
            }
        } else {
            throw new ErrorException("该订单还未结束试验,无法生产报告!");
        }
        return 0;
    }
    //解压文件夹
    private void unzip(File zipFile, File destDir) throws IOException {
        try (ZipFile zip = new ZipFile(zipFile)) {
            Enumeration<? extends ZipEntry> 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 inputStream = this.getClass().getResourceAsStream("/lib/license.xml");
            /*String url;
            try {
                InputStream inputStream = this.getClass().getResourceAsStream("/lib/license.xml");
                File file = File.createTempFile("temp", ".tmp");
                OutputStream outputStream = new FileOutputStream(file);
                IOUtils.copy(inputStream, outputStream);
                url = file.getAbsolutePath();
            } catch (FileNotFoundException e) {
                throw new ErrorException("找不到模板文件");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }*/
            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);
            TableCollection tables = doc.getFirstSection().getBody().getTables();
            for (Table table : tables) {
                RowCollection rows = table.getRows();
                table.setAllowAutoFit(false);
                for (Row row : rows) {
                    CellCollection cells = row.getCells();
                    for (Cell cell : cells) {
                        CellFormat cellFormat = cell.getCellFormat();
                        cellFormat.setFitText(false);  //设置自适应关闭
                        cellFormat.setWrapText(true);  // 设置自动换行
                    }
                }
            }
            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();
    }
    //生成报告
    private void generateReport(Integer orderId) {
        LocalDateTime now = LocalDateTime.now();
        InsOrder insOrder = insOrderMapper.selectById(orderId);
        //委托部门 departLims
        String departLims = userMapper.selectDepartLims(insOrder.getPrepareUser());
        //samples是过滤掉没有检验项目的样品
        List<SampleProductDto> samples = insSampleMapper.selectSampleProductListByOrderId(orderId);
        if (samples.size()==0){
            samples=insSampleMapper.selectSampleProductListByOrder2Id(orderId);
        }
        String sampleCode = samples.get(0).getSampleCode();
        InsReport insReport = new InsReport();
        insReport.setCode(insOrder.getEntrustCode());
        insReport.setInsOrderId(orderId);
        List<Map<String, Object>> tables = new ArrayList<>();
        Set<String> standardMethod = new HashSet<>();
        Set<String> deviceSet = new HashSet<>();
        Set<String> models = new HashSet<>();
        AtomicReference<Integer> productSize = new AtomicReference<>(0);
        AtomicReference<Integer> productSize1 = new AtomicReference<>(0);
        AtomicReference<Integer> productSize2 = new AtomicReference<>(0);
        AtomicReference<Integer> productSize3 = new AtomicReference<>(0);
        String[] monthNames = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
        samples.forEach(s -> {
            models.add(s.getModel());
            standardMethod.add(insOrderMapper.getStandardMethodCode(s.getStandardMethodListId()));
            //总数
            Long productCount = insProductMapper.selectCount(Wrappers.<InsProduct>lambdaQuery().eq(InsProduct::getInsSampleId, s.getId()));
            productSize.set(productSize.get() + Integer.parseInt(productCount + ""));
            //不判定
            Long productCount1 = insProductMapper.selectCount(Wrappers.<InsProduct>lambdaQuery()
                    .eq(InsProduct::getInsSampleId, s.getId())
                    .eq(InsProduct::getInsResult,3));
            productSize1.set(productSize1.get() + Integer.parseInt(productCount1 + ""));
            //不合格
            Long productCount2 = insProductMapper.selectCount(Wrappers.<InsProduct>lambdaQuery()
                    .eq(InsProduct::getInsSampleId, s.getId())
                    .eq(InsProduct::getInsResult,0));
            productSize2.set(productSize2.get() + Integer.parseInt(productCount2 + ""));
            //合格
            Long productCount3 = insProductMapper.selectCount(Wrappers.<InsProduct>lambdaQuery()
                    .eq(InsProduct::getInsSampleId, s.getId())
                    .eq(InsProduct::getInsResult,1));
            productSize3.set(productSize3.get() + Integer.parseInt(productCount3 + ""));
            for (InsProduct b : s.getInsProduct()) {
                if (b.getInsProductResult() != null) {
                    List<JSONObject> jsonObjects = JSON.parseArray(b.getInsProductResult().getEquipValue(), JSONObject.class);
                    for (JSONObject jsonObject : jsonObjects) {
                        if (!"".equals(jsonObject.get("v") + "")) {
                            deviceSet.add(jsonObject.get("v") + "");
                        }
                    }
                }
                if (b.getInsProductResult2() != null) {
                    for (InsProductResult2 jsonObject : b.getInsProductResult2()) {
                        if (jsonObject.getEquipValue() != null) {
                            deviceSet.add(jsonObject.getEquipValue());
                        }
                    }
                }
            }
        });
        String url;
        try {
            InputStream inputStream = this.getClass().getResourceAsStream("/static/report-template.docx");
            File file = File.createTempFile("temp", ".tmp");
            OutputStream outputStream = new FileOutputStream(file);
            IOUtils.copy(inputStream, outputStream);
            url = file.getAbsolutePath();
        } catch (FileNotFoundException e) {
            throw new ErrorException("找不到模板文件");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        StringBuilder standardMethod2 = new StringBuilder();
        for (String s : standardMethod) {
            standardMethod2.append("、").append(s);
        }
        standardMethod2.replace(0, 1, "");
        tables.forEach(table -> {
            table.put("tableSize", tables.size() + 1);
        });
        List<Map<String, String>> deviceList = null;
        if (deviceSet.size() != 0) {
            deviceList = insOrderMapper.selectDeviceList(deviceSet);
        }
        Map<String, String> codeStr = new HashMap<>();
        codeStr.put("报告编号", insReport.getCode());
        codeStr.put("样品名称", insOrder.getSample());
        codeStr.put("规格型号", samples.get(0).getModel());
        codeStr.put("发放日期", now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        String codePath;
        try {
            codePath = new MatrixToImageWriter().code(JackSonUtil.marshal(codeStr).replaceAll("\\{", "")
                    .replaceAll("}", "").replaceAll(",", "").replaceAll("\"", ""), twoCode);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String modelStr = "";
        for (String model : models) {
            modelStr += "," + model;
        }
        String finalModelStr = modelStr;
        String sampleEn = insSampleMapper.getSampleEn(insOrder.getSample());
        String orderType = insOrderMapper.getEnumLabelByValue(insOrder.getOrderType());
        String formType = insOrderMapper.getEnumLabelByValue(insOrder.getFormType());
        ConfigureBuilder builder = Configure.builder();
        builder.useSpringEL(true);
        List<Map<String, String>> finalDeviceList = deviceList;
        List<Map<String, String>> sampleList = insSampleMapper.selectSampleList(orderId);
        Integer userId = insSampleUserMapper.selectOne(Wrappers.<InsSampleUser>lambdaQuery()
                .eq(InsSampleUser::getInsSampleId, orderId).last("limit 1")).getUserId();
        String signatureUrl;
        try {
            signatureUrl = userMapper.selectById(userId).getSignatureUrl();
        } catch (Exception e) {
            throw new ErrorException("找不到检验人的签名");
        }
        if (ObjectUtils.isEmpty(signatureUrl) || signatureUrl.equals("")) {
            throw new ErrorException("找不到检验人的签名");
        }
        Custom custom = customMapper.selectById(insOrder.getCompanyId());
        /*获取附件图片类型*/
        List<Map<String, Object>> images = new ArrayList<>();
        List<InsOrderFile> insOrderFiles = insOrderFileMapper.selectList(Wrappers.<InsOrderFile>lambdaQuery().eq(InsOrderFile::getType, 1).eq(InsOrderFile::getInsOrderId, orderId));
        if (CollectionUtils.isNotEmpty(insOrderFiles)) {
            insOrderFiles.forEach(insOrderFile -> {
                Map<String, Object> image = new HashMap<>();
                PictureRenderData pictureRenderData = Pictures.ofLocal(imgUrl + "/" + insOrderFile.getFileUrl()).sizeInCm(17, 20).create();
                image.put("url", pictureRenderData);
                image.put("report", insReport);
                images.add(image);
            });
        }
        //委托人和电话字段判断
        if (ObjectUtils.isEmpty(insOrder.getPrepareUser())) {
            insOrder.setPrepareUser("/");
        }
        if (ObjectUtils.isEmpty(insOrder.getPhone())) {
            insOrder.setPhone("/");
        }
        //检验项目的环境
        InsProduct insProduct = insProductMapper.selectList(Wrappers.<InsProduct>lambdaQuery().eq(InsProduct::getState, 1).eq(InsProduct::getInsSampleId, samples.get(0).getId())).get(0);
        String environment = "";
        environment = (ObjectUtils.isNotEmpty(insProduct.getTemperature()) ? insProduct.getTemperature() + "℃ " : "") + (ObjectUtils.isNotEmpty(insProduct.getHumidity()) ? insProduct.getHumidity() + "%" : "");
        String finalEnvironment = environment;
        List<SampleProductDto> finalSamples = samples;
        XWPFTemplate template = XWPFTemplate.compile(url, builder.build()).render(
                new HashMap<String, Object>() {{
                    put("order", insOrder);
                    put("report", insReport);
                    put("departLims", departLims);
                    put("sampleCode", sampleCode);
                    put("environment", finalEnvironment);
                    put("custom", custom);
                    put("sampleSize", finalSamples.size());
                    put("tables", tables);
                    put("tableSize", tables.size() + 1);
                    put("standardMethod", (standardMethod2.toString().equals("null") ? "" : standardMethod2));
                    put("deviceList", finalDeviceList);
                    put("sampleList", sampleList);
                    put("twoCode", Pictures.ofLocal(codePath).create());
                    put("models", finalModelStr.replace(",", ""));
                    put("productSize", productSize);
                    put("productSize1", productSize1);
                    put("productSize2", productSize2);
                    put("productSize3", productSize3);
                    put("createTime", now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
                    put("createTimeEn", monthNames[now.getMonthValue() - 1] + " " + now.getDayOfMonth() + ", " + now.getYear());
                    put("insTime", insOrder.getInsTime().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
                    put("insTimeEn", monthNames[insOrder.getInsTime().getMonthValue() - 1] + " " + insOrder.getInsTime().getDayOfMonth() + ", " + insOrder.getInsTime().getYear());
                    put("writeUrl", null);
                    put("insUrl", Pictures.ofLocal(imgUrl + "/" + signatureUrl).create());
                    put("images", images);
                    put("examineUrl", null);
                    put("ratifyUrl", null);
                    put("sampleEn", sampleEn);
                    put("orderType", orderType);
                    put("getTime", insOrder.getExamineTime().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")));
                    put("getTimeEn", monthNames[insOrder.getExamineTime().getMonthValue() - 1] + " " + insOrder.getExamineTime().getDayOfMonth() + ", " + insOrder.getExamineTime().getYear());
                    put("seal1", null);
                    put("seal2", null);
                    put("formTypeCh", formType);
                    put("formTypeEn", insOrder.getFormType());
                }});
        try {
            String name = insReport.getCode().replace("/", "") + ".docx";
            template.writeAndClose(Files.newOutputStream(Paths.get(wordUrl + "/" + name)));
            insReport.setUrl("/word/" + name);
            insReportMapper.insert(insReport);
            insOrder.setInsState(5);
            insOrderMapper.updateById(insOrder);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 处理合并单元格的问题
        String path = wordUrl + "/" + insReport.getCode().replace("/", "") + ".docx";
        try {
            FileInputStream stream = new FileInputStream(path);
            XWPFDocument document = new XWPFDocument(stream);
            List<XWPFTable> xwpfTables = document.getTables();
            for (int i = 1; i < xwpfTables.size() - (deviceList == null ? 1 : 2); i++) {
                Set<String> set1 = new HashSet<>();
                Map<String, Map<String, Integer>> maps = new HashMap<>();
                for (int j = 0; j < xwpfTables.get(i).getRows().size(); j++) {
                    for (int k = 0; k < xwpfTables.get(i).getRows().get(j).getTableCells().size(); k++) {
                        if (xwpfTables.get(i).getRows().get(j).getTableCells().get(k).getText().indexOf("∑") > -1) {
                            String[] split = xwpfTables.get(i).getRows().get(j).getTableCells().get(k).getText().split("∑");
                            if (set1.add(split[1])) {
                                Map<String, Integer> map = new HashMap<>();
                                map.put("sr", j);
                                map.put("sc", k);
                                map.put("er", j + 0);
                                map.put("ec", k + 0);
                                maps.put(split[1], map);
                            } else {
                                Map<String, Integer> map1 = maps.get(split[1]);
                                if (j == map1.get("sr")) {
                                    map1.put("ec", map1.get("ec") + 1);
                                } else if (k == map1.get("sc")) {
                                    map1.put("er", map1.get("er") + 1);
                                }
                            }
                            String str = xwpfTables.get(i).getRows().get(j).getTableCells().get(k).getText().split("∑")[0];
                            xwpfTables.get(i).getRows().get(j).getTableCells().get(k).removeParagraph(0);
                            xwpfTables.get(i).getRows().get(j).getTableCells().get(k).setText(str);
                            xwpfTables.get(i).getRows().get(j).getTableCells().get(k).setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
                            xwpfTables.get(i).getRows().get(j).getTableCells().get(k).getParagraphArray(0).setAlignment(org.apache.poi.xwpf.usermodel.ParagraphAlignment.CENTER);
                        }
                    }
                }
                List<String> list = new ArrayList<>();
                for (String s : maps.keySet()) {
                    list.add(s);
                }
                for (int a = list.size() - 1; a >= 0; a--) {
                    Map<String, Integer> v = maps.get(list.get(a));
                    for (int j = 0; j < v.get("er") - v.get("sr") + 1; j++) {
                        if (v.get("ec") > v.get("sc")) {
                            try {
                                TableTools.mergeCellsHorizonal(xwpfTables.get(i), v.get("sr") + j, v.get("sc"), v.get("ec"));
                            } catch (Exception e) {
                            }
                        }
                    }
                    if (v.get("er") > v.get("sr")) {
                        try {
                            TableTools.mergeCellsVertically(xwpfTables.get(i), v.get("sc"), v.get("sr"), v.get("er"));
                        } catch (Exception e) {
                        }
                    }
                }
            }
            FileOutputStream fileOutputStream = new FileOutputStream(path);
            document.write(fileOutputStream);
            fileOutputStream.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //处理中英文换行的问题
        try {
            FileInputStream stream1 = new FileInputStream(path);
            XWPFDocument document1 = new XWPFDocument(stream1);
            List<XWPFTable> xwpfTables1 = document1.getTables();
            for (int i = 1; i < xwpfTables1.size() - (deviceList == null ? 1 : 2); i++) {
                for (int j = 0; j < xwpfTables1.get(i).getRows().size(); j++) {
                    for (int k = 0; k < xwpfTables1.get(i).getRows().get(j).getTableCells().size(); k++) {
                        if (xwpfTables1.get(i).getRows().get(j).getTableCells().get(k).getText().contains("@")) {
                            String text = xwpfTables1.get(i).getRows().get(j).getTableCells().get(k).getText();
                            String[] split = text.split("@");
                            xwpfTables1.get(i).getRows().get(j).getTableCells().get(k).removeParagraph(0);
                            XWPFParagraph xwpfParagraph = xwpfTables1.get(i).getRows().get(j).getTableCells().get(k).addParagraph();
                            XWPFRun run = xwpfParagraph.createRun();
                            run.setText(split[0]);
                            if (ObjectUtils.isNotNull(split[1])) {
                                run.addBreak();
                                run.setText(split[1]);
                            }
                            xwpfParagraph.setAlignment(org.apache.poi.xwpf.usermodel.ParagraphAlignment.CENTER);
                        }
                    }
                }
            }
            FileOutputStream fileOutputStream1 = new FileOutputStream(path);
            document1.write(fileOutputStream1);
            fileOutputStream1.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    // 计算行高的方法
    private int calculateRowHeight(RowRenderData rowRenderData) {
        // 实现计算逻辑,可能需要根据单元格内容和字体等参数进行计算
        int height = 0;
        for (CellRenderData cell : rowRenderData.getCells()) {
            int cellHeight = estimateCellHeight(cell); // 根据内容估算单元格高度
            if (cellHeight > height) {
                height = cellHeight;
            }
        }
        return height;
    }
    //根据单元格的文本内容计算实际行高
    private int estimateCellHeight(CellRenderData cellRenderData) {
        // 假设默认行高是40
        int defaultHeight = 40;
        // 获取单元格中的所有段落
        List<ParagraphRenderData> paragraphs = cellRenderData.getParagraphs();
        int estimatedHeight = 0;
        // 遍历段落,估算每个段落的高度
        for (ParagraphRenderData paragraph : paragraphs) {
            List<RenderData> contents = paragraph.getContents();
            for (RenderData content : contents) {
                if (content instanceof TextRenderData) {
                    TextRenderData text = (TextRenderData) content;
                    Style style = text.getStyle();
                    // 假设每行文本的高度为字体大小的1.2倍
                    Double fontSize = Objects.isNull(style.getFontSize()) ? 12.0 : style.getFontSize();
                    int lines = (int) Math.ceil(text.getText().length() / 15.0); // 假设每行约15个字符
                    int textHeight = (int) (fontSize * 1.2 * lines);
                    // 累加段落的高度
                    estimatedHeight += textHeight;
                }
            }
        }
        // 返回最大值,确保高度不低于默认高度
        return Math.max(estimatedHeight, defaultHeight);
    }
    private void getTemplateThing(Set<Integer> set, Map<Integer, String> map2, List<InsProduct> insProducts) {
        for (InsProduct product : insProducts) {
            if (product.getTemplateId() == null) {
                product.setTemplate(new ArrayList<>());
                continue;
            }
            String thing = null;
            if (product.getTemplateId() != null && set.add(product.getTemplateId())) {
                map2.put(product.getTemplateId(), standardTemplateService.getStandTempThingById(product.getTemplateId()) + "");
                thing = map2.get(product.getTemplateId());
            }
            if (StrUtil.isNotEmpty(thing)) {
                JSONObject sheet = JSON.parseObject(JSON.toJSONString(JSON.parseArray(JSON.toJSONString(JSON.parseObject(thing).get("data"))).get(0)));
                JSONObject config = JSON.parseObject(JSON.toJSONString(sheet.get("config")));
                List<JSONObject> cellData = JSON.parseArray(JSON.toJSONString(sheet.get("celldata")), JSONObject.class);
                Map<String, Object> style = new HashMap<>();
                style.put("rowlen", config.get("rowlen"));
                style.put("columnlen", config.get("columnlen"));
                product.setTemplate(cellData);
                product.setStyle(style);
                product.setTemplateName(standardTemplateService.getStandTempNameById(product.getTemplateId()));
            }
        }
    }
}