吴羡
2026-10-24 3d397976d08f0359b8cfeb4e4f22403ae5d0c04f
inspect-server/src/main/java/com/ruoyi/inspect/service/impl/InsReportServiceImpl.java
@@ -1,6 +1,5 @@
package com.ruoyi.inspect.service.impl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
@@ -36,6 +35,7 @@
import com.ruoyi.common.constant.InsOrderTypeConstants;
import com.ruoyi.common.constant.MenuJumpPathConstants;
import com.ruoyi.common.core.domain.Result;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.InformationNotification;
import com.ruoyi.common.utils.DateImageUtil;
import com.ruoyi.common.utils.QueryWrappers;
@@ -54,7 +54,10 @@
import com.ruoyi.inspect.util.ReportSealLayoutUtil;
import com.ruoyi.inspect.util.ReportSignaturePictureUtils;
import com.ruoyi.system.mapper.UserMapper;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.InformationNotificationService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
@@ -66,9 +69,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.Resource;
import javax.imageio.ImageIO;
import jakarta.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
@@ -112,6 +113,8 @@
    private InsProductMapper insProductMapper;
    @Resource
    private InformationNotificationService informationNotificationService;
    @Resource
    private ISysMenuService menuService;
    @Value("${wordUrl}")
    private String wordUrl;
    @Value("${file.path}")
@@ -199,6 +202,7 @@
        if (userId == null) {
            throw new ErrorException("缺少审核人");
        }
        ensureReportPreparationPermission(userId, "审核人");
        insReport.setExamineUserId(userId);//审核人
        insReport.setWriteTime(LocalDateTime.now());//提交时间
        //获取提交人的签名地址
@@ -227,8 +231,6 @@
        info.setViewStatus(false);
        info.setJumpPath(MenuJumpPathConstants.REPORT_PREPARATION);
        informationNotificationService.addInformationNotification(info);
        String primaryReportUrl = getPrimaryReportUrl(insReport);
        // 判断是否是原材料  需要替换****成供应商
        IfsInventoryQuantity one = ifsInventoryQuantityMapper.selectOne(new LambdaQueryWrapper<IfsInventoryQuantity>()
                .eq(IfsInventoryQuantity::getId, order.getIfsInventoryId()));
@@ -249,9 +251,7 @@
        }};
        writeMarksToReportFiles(insReport, writeMarks);
        // 修改临时pdf
        String tempUrlPdf = wordToPdfTemp(primaryReportUrl.replace("/word", wordUrl));
        insReport.setTempUrlPdf("/word/" + tempUrlPdf);
        refreshTemporaryPreviews(insReport);
        insReportMapper.updateById(insReport);
@@ -264,6 +264,33 @@
                .set(InsReport::getIsExamine, null));
        return 1;
    }
    /**
     * 指定审核人/批准人时,确认对方登录后能看到「报告编制」页面,
     * 避免指定后登录只剩首页、无法继续审批。
     */
    private void ensureReportPreparationPermission(Integer userId, String userLabel) {
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId.longValue());
        if (!containsReportPreparation(menus)) {
            throw new ErrorException("所选" + userLabel + "没有「业务管理 → 报告编制」页面权限,请先在「系统管理 → 用户管理」为其分配对应角色");
        }
    }
    private boolean containsReportPreparation(List<SysMenu> menus) {
        if (CollectionUtils.isEmpty(menus)) {
            return false;
        }
        for (SysMenu menu : menus) {
            if (Long.valueOf(1129L).equals(menu.getMenuId())
                    || "reportPreparation".equals(menu.getPath())) {
                return true;
            }
            if (containsReportPreparation(menu.getChildren())) {
                return true;
            }
        }
        return false;
    }
    //审核
@@ -321,6 +348,7 @@
            if (userId == null) {
                throw new ErrorException("缺少批准人");
            }
            ensureReportPreparationPermission(userId, "批准人");
            if (Objects.equals(insReport.getExamineUserId(), userId)) {
                throw new ErrorException("审核人和批准人不能为同一人,请重新选择批准人");
            }
@@ -351,16 +379,13 @@
        info.setViewStatus(false);
        info.setJumpPath(MenuJumpPathConstants.REPORT_PREPARATION);
        informationNotificationService.addInformationNotification(info);
        String primaryReportUrl = getPrimaryReportUrl(insReport);
        Map<String, Object> examineMarks = new HashMap<String, Object>() {{
            put("examineUrl", ReportSignaturePictureUtils.create(imgUrl, signatureUrl));
            put("examineDateUrl", Pictures.ofStream(DateImageUtil.createDateImage(null)).create());
        }};
        writeMarksToReportFiles(insReport, examineMarks);
        // 修改临时pdf
        String tempUrlPdf = wordToPdfTemp(primaryReportUrl.replace("/word", wordUrl));
        insReport.setTempUrlPdf("/word/" + tempUrlPdf);
        refreshTemporaryPreviews(insReport);
        // 发送企业微信通知(通知批准人审批)
        threadPoolTaskExecutor.execute(() -> {
@@ -384,11 +409,11 @@
                message += "\n批次号: " + ifsInventoryQuantity.getUpdateBatchNo();
            }
            //发送企业微信消息通知  提交复核
            try {
                WxCpUtils.inform(sendUserAccount, message, null);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
//            try {
//                WxCpUtils.inform(sendUserAccount, message, null);
//            } catch (Exception e) {
//                throw new RuntimeException(e);
//            }
        });
        insReportMapper.updateById(insReport);
@@ -696,6 +721,30 @@
                .collect(Collectors.toList());
    }
    private void refreshTemporaryPreviews(InsReport report) {
        String primaryPdf = wordToPdfTemp(getPrimaryReportUrl(report).replace("/word", wordUrl));
        if (StringUtils.isBlank(primaryPdf)) {
            throw new ErrorException("检测报告预览生成失败");
        }
        report.setTempUrlPdf("/word/" + primaryPdf);
        if (StringUtils.isNotBlank(report.getInspectionUrl())) {
            String inspectionPdf = wordToPdfTemp(report.getInspectionUrl().replace("/word", wordUrl));
            if (StringUtils.isBlank(inspectionPdf)) {
                throw new ErrorException("检验报告预览生成失败");
            }
            report.setInspectionTempUrlPdf("/word/" + inspectionPdf);
        }
    }
    @Override
    public String prepareEditedReportPreview(String absoluteDocxPath) {
        String pdfName = wordToPdfTemp(absoluteDocxPath);
        if (StringUtils.isBlank(pdfName)) {
            throw new ErrorException("报告预览生成失败");
        }
        return "/word/" + pdfName;
    }
    private void writeMarksToReportFiles(InsReport report, Map<String, Object> marks) {
        for (String reportUrl : getApprovalReportUrls(report)) {
            wordInsertUrl(marks, reportUrl.replace("/word", wordUrl));
@@ -772,7 +821,12 @@
            throw new ErrorException("报告文件不存在,请联系管理员");
        }
        try {
            String filename = file.getFileName().toString();
            // 物理文件可能是 reviewed/edited UUID;对用户始终使用业务报告编号。
            String reportNumber = StringUtils.isBlank(report.getCode()) ? "报告" : report.getCode();
            reportNumber = reportNumber.replaceAll("[\\\\/:*?\"<>|\\p{Cntrl}]", "-").trim();
            String suffix = StringUtils.isNotBlank(report.getInspectionUrl())
                    ? (Objects.equals(reportType, INSPECTION_REPORT) ? "-检验报告" : "-检测报告") : "";
            String filename = reportNumber + suffix + ".docx";
            String encodedName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20");
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedName);