Ver código fonte

feature 增加文件预览+水印的功能

xiahan 1 mês atrás
pai
commit
3cd2f72a58

+ 1 - 5
qhse-common/src/main/java/com/rongwei/bscommon/sys/service/FileFormatConversionService.java

@@ -1,8 +1,6 @@
 package com.rongwei.bscommon.sys.service;
 
 import javax.servlet.http.HttpServletResponse;
-import java.io.UnsupportedEncodingException;
-import java.util.Map;
 
 /**
  * FileFormatConversionService class
@@ -11,7 +9,5 @@ import java.util.Map;
  * @date 2025/08/01
  */
 public interface FileFormatConversionService {
-    void fileFormatConversion(String id, HttpServletResponse response);
-
-
+    void fileFormatConversion(String id,  HttpServletResponse response,boolean waterMark);
 }

+ 2 - 0
qhse-common/src/main/java/com/rongwei/bscommon/sys/service/QhseTargetResponsibilityDocumentService.java

@@ -15,4 +15,6 @@ import java.util.Map;
 public interface QhseTargetResponsibilityDocumentService extends IService<QhseTargetResponsibilityDocumentDo> {
 
     void lettersOfResponsibilitySignaturePreview(@RequestBody Map<String, String> mapData, HttpServletResponse response);
+
+    void zipDownload(String id, HttpServletResponse response);
 }

+ 278 - 34
qhse-common/src/main/java/com/rongwei/bscommon/sys/service/impl/FileFormatConversionServiceImpl.java

@@ -1,10 +1,17 @@
 package com.rongwei.bscommon.sys.service.impl;
 
 import com.aspose.cells.*;
+import com.aspose.pdf.FontRepository;
+import com.aspose.pdf.Page;
+import com.aspose.pdf.TextStamp;
+import com.aspose.pdf.TextState;
 import com.aspose.words.Document;
-import com.aspose.words.SaveOutputParameters;
+import com.aspose.words.SaveOptions;
 import com.rongwei.bscommon.sys.service.FileFormatConversionService;
 import com.rongwei.bscommon.sys.utils.AsposeLicenseConfig;
+import com.rongwei.bscommon.sys.utils.QHSEConstant;
+import com.rongwei.bscommon.sys.utils.QHSEUtils;
+import com.rongwei.rwadmincommon.system.vo.SysUserVo;
 import com.rongwei.rwcommon.base.exception.CustomException;
 import com.rongwei.rwcommon.utils.StringUtils;
 import com.rongwei.rwcommonentity.commonservers.domain.SysFileItemDo;
@@ -13,13 +20,22 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.imageio.ImageIO;
 import javax.servlet.http.HttpServletResponse;
+import java.awt.*;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.URLEncoder;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 
+import static com.rongwei.bscommon.sys.utils.QHSEConstant.ContentType.STREAM;
+import static com.rongwei.bscommon.sys.utils.QHSEConstant.DEFAULT_WATER_MARK;
 import static com.rongwei.bscommon.sys.utils.QHSEConstant.FileType.*;
 
 /**
@@ -43,8 +59,17 @@ public class FileFormatConversionServiceImpl implements FileFormatConversionServ
         return sysFileItemDo;
     }
 
+    /**
+     * 文件预览并添加PDF
+     * 特殊格式转为PDF
+     * 特殊 格式添加PDF
+     *
+     * @param id
+     * @param response
+     * @param waterMark
+     */
     @Override
-    public void fileFormatConversion(String id, HttpServletResponse response) {
+    public void fileFormatConversion(String id, HttpServletResponse response, boolean waterMark) {
         log.info("开始进行文件格式转换Id为:{}", id);
         if (StringUtils.isBlank(id)) {
             log.error("参数异常");
@@ -59,18 +84,31 @@ public class FileFormatConversionServiceImpl implements FileFormatConversionServ
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
-        response.setContentType("application/pdf");
+
         response.setHeader("Content-Disposition", "inline; filename=" + fileName);
         response.setHeader("X-Content-Length", String.valueOf(sysFileItemDo.getFilesize()));
+        String waterMarkStr = "";
+        if (waterMark) {
+            SysUserVo currentUser = QHSEUtils.getCurrentUser();
+            waterMarkStr = String.format(DEFAULT_WATER_MARK, currentUser.getAccount(), currentUser.getName());
+        }
+
 
         if (XLSX.equals(lowerCaseFileTYpe) || XLS.equals(lowerCaseFileTYpe)) {
+            response.setContentType(QHSEConstant.ContentType.PDF);
             AsposeLicenseConfig.getExcelLicense();
-            convertExcelToPdf(null, fullpath, response);
+            convertExcelToPdf(fullpath, response, waterMark, waterMarkStr);
         } else if (DOCX.equals(lowerCaseFileTYpe) || DOC.equals(lowerCaseFileTYpe)) {
-            convertWordToPdf(null, fullpath, response);
+            response.setContentType(QHSEConstant.ContentType.PDF);
+            convertWordToPdf(fullpath, response, waterMark, waterMarkStr);
+        } else if (PDF.equals(lowerCaseFileTYpe)) {
+            response.setContentType(QHSEConstant.ContentType.PDF);
+            pdfDispose(fullpath, response, waterMark, waterMarkStr);
+        } else if ((PNG.equals(lowerCaseFileTYpe) || JPEG.equals(lowerCaseFileTYpe) || JPG.equals(lowerCaseFileTYpe)) && waterMark) {
+            pictureDispose(fullpath, response, waterMarkStr,lowerCaseFileTYpe);
         } else {
             try {
-                response.setContentType("application/octet-stream");
+                response.setContentType(STREAM);
                 Files.copy(Paths.get(fullpath), response.getOutputStream());
             } catch (Exception e) {
                 log.error("文件名:{}格式化失败- 原因: {} | 异常类型: {}", sysFileItemDo.getFilename(), e.getMessage(), e.getClass().getSimpleName(), e);
@@ -80,46 +118,252 @@ public class FileFormatConversionServiceImpl implements FileFormatConversionServ
         }
     }
 
-
-    public void convertExcelToPdf(InputStream inputStream, String fullPath, HttpServletResponse response) {
-
+    /**
+     * 图片处理
+     *
+     * @param fullPath
+     * @param response
+     * @param waterMarkStr
+     */
+    public void pictureDispose(String fullPath, HttpServletResponse response, String waterMarkStr, String formatName) {
         try (OutputStream out = response.getOutputStream();
              InputStream templateStream = Files.newInputStream(Paths.get(fullPath))) {
-            LoadOptions loadOptions = new LoadOptions(LoadFormat.XLSX);
-            loadOptions.setMemorySetting(MemorySetting.MEMORY_PREFERENCE);
-            Workbook workbook = new Workbook(templateStream, loadOptions);
-            Worksheet worksheet = workbook.getWorksheets().get(0);
-            // 自动调整所有列的宽度
-            worksheet.autoFitColumns();
-            // 设置 PDF 转换选项
-            PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
-            pdfSaveOptions.setOnePagePerSheet(true); // 每个工作表单独一页
-            pdfSaveOptions.setAllColumnsInOnePagePerSheet(true); // 所有列在一页
-            workbook.calculateFormula();
-            // 转换为 PDF 并输出到流
-            workbook.save(out, pdfSaveOptions);
-            out.flush();
+
+            BufferedImage originalImage = ImageIO.read(templateStream);
+
+            // 创建目标图像(保留透明度)
+            int imageType = originalImage.getTransparency() == BufferedImage.TRANSLUCENT
+                    ? BufferedImage.TYPE_INT_ARGB
+                    : BufferedImage.TYPE_INT_RGB;
+            BufferedImage newImage = new BufferedImage(
+                    originalImage.getWidth(),
+                    originalImage.getHeight(),
+                    imageType
+            );
+
+            // 将原始图像绘制到新图像
+            Graphics2D g2d = newImage.createGraphics();
+            g2d.drawImage(originalImage, 0, 0, null);
+
+            // 设置高质量渲染
+            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+            g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+            // 设置水印字体和颜色
+            Font font = new Font("微软雅黑", Font.BOLD, 15);
+            g2d.setFont(font);
+            g2d.setColor(Color.lightGray);
+            // 循环平铺水印
+            for (int x = 0; x < newImage.getWidth() ; x += 200) {
+                for (int y = 0; y < newImage.getHeight() ; y += 100) {
+                    // 设置旋转中心点
+                    g2d.rotate(Math.toRadians(-45), x, y);
+                    g2d.drawString(waterMarkStr, x, y);
+                    // 重置旋转(避免累积旋转)
+                    g2d.rotate(Math.toRadians(45), x, y);
+                }
+            }
+            g2d.dispose();
+            // 设置响应类型
+            if ("JPEG".equalsIgnoreCase(formatName) || "JPG".equalsIgnoreCase(formatName)) {
+                response.setContentType("image/jpeg");
+                // 处理JPEG透明度
+                BufferedImage jpegImage = new BufferedImage(
+                        newImage.getWidth(),
+                        newImage.getHeight(),
+                        BufferedImage.TYPE_INT_RGB
+                );
+                Graphics2D g = jpegImage.createGraphics();
+                g.drawImage(newImage, 0, 0, Color.WHITE, null);
+                g.dispose();
+                ImageIO.write(jpegImage, formatName, out);
+            } else {
+                response.setContentType("image/png");
+                ImageIO.write(newImage, formatName, out);
+            }
         } catch (Exception e) {
-            log.error("excel转pdf失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
-            throw new RuntimeException("获取预览文件失败!请联系系统管理员");
+            log.error("图片处理失败", e);
+            throw new RuntimeException("文件处理异常");
         }
     }
 
-    public void convertWordToPdf(InputStream inputStream, String fullPath, HttpServletResponse response) {
+    /**
+     * pdf 处理
+     *
+     * @param fullPath
+     * @param response
+     * @param waterMark
+     * @param waterMarkStr
+     */
+    public void pdfDispose(String fullPath, HttpServletResponse response, boolean waterMark, String waterMarkStr) {
         try (OutputStream out = response.getOutputStream();
              InputStream templateStream = Files.newInputStream(Paths.get(fullPath))) {
-            Document doc = new Document(templateStream);
-            // 设置 PDF 转换选项
-            PdfSaveOptions options = new PdfSaveOptions();
-            options.setCompliance(PdfCompliance.PDF_A_1_A); // 设置PDF/A-1a标准
-            // 3. 直接输出到响应流(避免中间文件)
-            SaveOutputParameters save = doc.save(out, com.aspose.words.SaveFormat.PDF);
-            // 4. 强制刷新缓冲区(确保数据完整传输)
+            com.aspose.pdf.Document pdfDoc = new com.aspose.pdf.Document(templateStream);
+            if (waterMark) {
+                addTextWatermark(pdfDoc, waterMarkStr, 0.5f);
+            }
+            // 转换为 PDF 并输出到流
+            pdfDoc.save(out);
             out.flush();
         } catch (Exception e) {
-            log.error("word转pdf失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
+            log.error("pdf预览失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
             throw new RuntimeException("获取预览文件失败!请联系系统管理员");
         }
     }
 
+    /**
+     * excel转PDF
+     *
+     * @param fullPath
+     * @param response
+     * @param waterMark
+     * @param waterMarkStr
+     */
+    public void convertExcelToPdf(String fullPath, HttpServletResponse response, boolean waterMark, String waterMarkStr) {
+        if (waterMark) {
+            try (ByteArrayOutputStream excelPdfStream = new ByteArrayOutputStream();
+                 InputStream templateStream = Files.newInputStream(Paths.get(fullPath));
+                 OutputStream out = response.getOutputStream();) {
+                // 1. Excel转PDF到内存流
+                LoadOptions loadOptions = new LoadOptions(LoadFormat.XLSX);
+                loadOptions.setMemorySetting(MemorySetting.MEMORY_PREFERENCE);
+                Workbook workbook = new Workbook(templateStream, loadOptions);
+                Worksheet worksheet = workbook.getWorksheets().get(0);
+                worksheet.autoFitColumns();
+                workbook.calculateFormula();
+                PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
+                pdfSaveOptions.setOnePagePerSheet(true);
+                // 关闭 "AllColumnsInOnePagePerSheet" 避免过度压缩
+                pdfSaveOptions.setAllColumnsInOnePagePerSheet(false);
+                // 调整优化策略(可选)
+                pdfSaveOptions.setOptimizationType(PdfOptimizationType.STANDARD); // 平衡质量与大小
+                pdfSaveOptions.setCompliance(PdfCompliance.PDF_A_1_A); // 符合标准格式
+                workbook.save(excelPdfStream, pdfSaveOptions);
+
+                // 2. 使用Aspose.PDF添加水印
+                try (com.aspose.pdf.Document pdfDoc = new com.aspose.pdf.Document(new ByteArrayInputStream(excelPdfStream.toByteArray()))) {
+                    addTextWatermark(pdfDoc, waterMarkStr, 0.5f);
+                    // 3. 输出最终PDF
+                    pdfDoc.save(out);
+                    out.flush();
+                }
+            } catch (Exception e) {
+                log.error("Excel转PDF失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
+                throw new RuntimeException("文件转换失败,请联系系统管理员");
+            }
+
+        } else {
+            try (OutputStream out = response.getOutputStream();
+                 InputStream templateStream = Files.newInputStream(Paths.get(fullPath))) {
+                LoadOptions loadOptions = new LoadOptions(LoadFormat.XLSX);
+                loadOptions.setMemorySetting(MemorySetting.MEMORY_PREFERENCE);
+                Workbook workbook = new Workbook(templateStream, loadOptions);
+                Worksheet worksheet = workbook.getWorksheets().get(0);
+                // 自动调整所有列的宽度
+                worksheet.autoFitColumns();
+                // 设置 PDF 转换选项
+                PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
+                pdfSaveOptions.setOnePagePerSheet(true); // 每个工作表单独一页
+                pdfSaveOptions.setAllColumnsInOnePagePerSheet(true); // 所有列在一页
+                pdfSaveOptions.setOptimizationType(PdfOptimizationType.MINIMUM_SIZE);
+                workbook.calculateFormula();
+                // 转换为 PDF 并输出到流
+                workbook.save(out, pdfSaveOptions);
+                out.flush();
+            } catch (Exception e) {
+                log.error("excel转pdf失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
+                throw new RuntimeException("获取预览文件失败!请联系系统管理员");
+            }
+        }
+
+    }
+
+    /**
+     * 添加文字水印
+     *
+     * @param pdfDoc
+     * @param watermarkText
+     * @param opacity
+     */
+    private void addTextWatermark(com.aspose.pdf.Document pdfDoc, String watermarkText, float opacity) {
+        for (Page page : pdfDoc.getPages()) {
+            // 获取页面实际尺寸(排除边距)
+            double width = page.getMediaBox().getWidth();
+            double height = page.getMediaBox().getHeight();
+
+            // 水印参数配置
+            int fontSize = 36;
+            double rotation = 45; // 启用旋转
+            double spacing = fontSize * 5; // 动态步长(根据字体大小调整)
+
+            // 创建文本样式
+            TextState textState = new TextState();
+            textState.setFontSize(fontSize);
+            textState.setForegroundColor(com.aspose.pdf.Color.getLightGray());
+            textState.setFont(FontRepository.findFont("Arial"));
+
+            // 平铺水印
+            for (double x = -100; x < width; x += spacing) {
+                for (double y = -800; y < height; y += spacing) {
+                    TextStamp textStamp = new TextStamp(watermarkText, textState);
+                    textStamp.setXIndent(x + 100);
+                    textStamp.setYIndent(y + 400);
+                    textStamp.setRotateAngle(rotation);
+                    textStamp.setOpacity(opacity);
+                    textStamp.setZoom(0.4);
+                    page.addStamp(textStamp);
+                }
+            }
+        }
+    }
+
+    /**
+     * word转PDF
+     *
+     * @param fullPath
+     * @param response
+     * @param waterMark
+     * @param waterMarkStr
+     */
+    public void convertWordToPdf(String fullPath, HttpServletResponse response, boolean waterMark, String waterMarkStr) {
+        if (waterMark) {
+            try (ByteArrayOutputStream excelPdfStream = new ByteArrayOutputStream();
+                 InputStream templateStream = Files.newInputStream(Paths.get(fullPath));
+                 OutputStream out = response.getOutputStream();) {
+
+                Document doc = new Document(templateStream);
+                SaveOptions options = new com.aspose.words.PdfSaveOptions();
+                options.setPrettyFormat(true); // 设置PDF/A-1a标准
+                doc.save(excelPdfStream, options);
+
+                // 2. 使用Aspose.PDF添加水印
+                try (com.aspose.pdf.Document pdfDoc = new com.aspose.pdf.Document(new ByteArrayInputStream(excelPdfStream.toByteArray()))) {
+                    addTextWatermark(pdfDoc, waterMarkStr, 0.5f);
+                    // 3. 输出最终PDF
+                    pdfDoc.save(out);
+                    out.flush();
+                }
+            } catch (Exception e) {
+                log.error("Excel转PDF失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
+                throw new RuntimeException("文件转换失败,请联系系统管理员");
+            }
+
+        } else {
+            try (OutputStream out = response.getOutputStream();
+                 InputStream templateStream = Files.newInputStream(Paths.get(fullPath))) {
+                Document doc = new Document(templateStream);
+                // 设置 PDF 转换选项
+                PdfSaveOptions options = new PdfSaveOptions();
+                options.setCompliance(PdfCompliance.PDF_A_1_A); // 设置PDF/A-1a标准
+                // 3. 直接输出到响应流(避免中间文件)
+                doc.save(out, com.aspose.words.SaveFormat.PDF);
+                // 4. 强制刷新缓冲区(确保数据完整传输)
+                out.flush();
+            } catch (Exception e) {
+                log.error("word转pdf失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
+                throw new RuntimeException("获取预览文件失败!请联系系统管理员");
+            }
+        }
+    }
+
 }

+ 178 - 8
qhse-common/src/main/java/com/rongwei/bscommon/sys/service/impl/QhseTargetResponsibilityDocumentServiceImpl.java

@@ -3,7 +3,8 @@ package com.rongwei.bscommon.sys.service.impl;
 import com.aspose.cells.PdfCompliance;
 import com.aspose.cells.PdfSaveOptions;
 import com.aspose.words.Document;
-import com.aspose.words.SaveOutputParameters;
+import com.aspose.words.SaveFormat;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.rongwei.bscommon.sys.dao.QhseTargetResponsibilityDocumentDao;
 import com.rongwei.bscommon.sys.service.QhseTargetResponsibilityDocumentService;
@@ -11,6 +12,7 @@ import com.rongwei.bscommon.sys.utils.WordMergeHandler;
 import com.rongwei.bscommon.sys.utils.WordUtils;
 import com.rongwei.bsentity.domain.QhseTargetResponsibilityDocumentDo;
 import com.rongwei.bsentity.domain.QhseTargetResponsibilityDocumentSignatureDo;
+import com.rongwei.rwcommon.base.BaseDo;
 import com.rongwei.rwcommon.base.exception.CustomException;
 import com.rongwei.rwcommon.utils.StringUtils;
 import com.rongwei.rwcommonentity.commonservers.domain.SysFileItemDo;
@@ -20,17 +22,23 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.servlet.http.HttpServletResponse;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
 import java.net.URLEncoder;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.Map;
+import java.text.SimpleDateFormat;
+import java.time.Year;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
+import static com.rongwei.bscommon.sys.utils.QHSEConstant.DatePattern.DATE_PATTERN_YMD_CN;
 import static com.rongwei.bscommon.sys.utils.QHSEConstant.FILE_SEPARATOR;
 import static com.rongwei.bscommon.sys.utils.QHSEConstant.FileType.DOC;
 import static com.rongwei.bscommon.sys.utils.QHSEConstant.FileType.DOCX;
+import static com.rongwei.bscommon.sys.utils.QHSEConstant.PartType.PARTY_A;
+import static com.rongwei.bscommon.sys.utils.QHSEConstant.PartType.PARTY_B;
 
 /**
  * @author libai
@@ -47,6 +55,8 @@ public class QhseTargetResponsibilityDocumentServiceImpl extends ServiceImpl<Qhs
 
 
     private static final Logger log = LoggerFactory.getLogger(QhseTargetResponsibilityDocumentServiceImpl.class);
+    @Autowired
+    private SysFileItemServiceImpl sysFileItemServiceImpl;
 
     @Override
     public void lettersOfResponsibilitySignaturePreview(Map<String, String> mapData, HttpServletResponse response) {
@@ -68,7 +78,7 @@ public class QhseTargetResponsibilityDocumentServiceImpl extends ServiceImpl<Qhs
         // 没有签名直接预览
         if (documentSignatureDo == null || StringUtils.isBlank(documentSignatureDo.getSignature())) {
             log.error("无法获取到签名信息");
-            fileFormatConversionService.fileFormatConversion(fileId, response);
+            fileFormatConversionService.fileFormatConversion(fileId, response, false);
             return;
         }
         // 甲方或者乙方
@@ -130,7 +140,7 @@ public class QhseTargetResponsibilityDocumentServiceImpl extends ServiceImpl<Qhs
             PdfSaveOptions options = new PdfSaveOptions();
             options.setCompliance(PdfCompliance.PDF_A_1_A); // 设置PDF/A-1a标准
             // 3. 直接输出到响应流(避免中间文件)
-            doc.save(out, com.aspose.words.SaveFormat.PDF);
+            doc.save(out, SaveFormat.PDF);
             // 4. 强制刷新缓冲区(确保数据完整传输)
             out.flush();
         } catch (Exception e) {
@@ -138,8 +148,168 @@ public class QhseTargetResponsibilityDocumentServiceImpl extends ServiceImpl<Qhs
             throw new RuntimeException("获取签名责任书失败!请联系系统管理员");
         }
     }
-}
 
+    public void docDispose() {
+
+    }
+
+    /**
+     * 压缩包下载
+     *
+     * @param id
+     * @param response
+     */
+    @Override
+    public void zipDownload(String id, HttpServletResponse response) {
+        QhseTargetResponsibilityDocumentDo qhseTargetResponsibilityDocumentDo = this.getById(id);
+        if (qhseTargetResponsibilityDocumentDo == null) {
+            log.error("无法获取到责任书信息");
+            throw new CustomException("该记录可能已被其他人删除,请联系系统管理员");
+        }
+        if (StringUtils.isBlank(qhseTargetResponsibilityDocumentDo.getResponsibilityfiles())) {
+            log.error("责任书目录不存在");
+            throw new CustomException("无法获取到责任书信息,请联系系统管理员");
+        }
+        String responsibilityfiles = qhseTargetResponsibilityDocumentDo.getResponsibilityfiles();
+        SysFileItemDo tempFile = sysFileItemServiceImpl.getById(responsibilityfiles.split(FILE_SEPARATOR, 2)[1]);
+        if (tempFile == null) {
+            log.error("责任书在目录中存在");
+            throw new CustomException("无法获取到责任书信息,请联系系统管理员");
+        }
+
+        if (StringUtils.isBlank(tempFile.getFullpath())) {
+            log.error("责任书在目录中存在");
+            throw new CustomException("无法获取到责任书信息,请联系系统管理员");
+        }
+
+
+        List<QhseTargetResponsibilityDocumentSignatureDo> documentSignatureDo = qhseTargetResponsibilityDocumentSignatureService
+                .list(new LambdaQueryWrapper<QhseTargetResponsibilityDocumentSignatureDo>()
+                        .eq(QhseTargetResponsibilityDocumentSignatureDo::getMainid, id)
+                        .eq(BaseDo::getDeleted, "0"));
+
+        boolean noSignatureData = documentSignatureDo.stream().anyMatch(info -> StringUtils.isNotBlank(info.getSignature()));
+        if (noSignatureData) {
+            throw new CustomException("目标责任书未含甲方及乙方的签名,无法下载!");
+        }
+
+        Map<String, String> signatureDataMap = documentSignatureDo.stream().filter(info -> StringUtils.isNotBlank(info.getSignature())).collect(Collectors.groupingBy(QhseTargetResponsibilityDocumentSignatureDo::getSignaturesource,
+                Collectors.mapping(info -> {
+                    String signature = info.getSignature();
+                    if (StringUtils.isNotBlank(signature)) {
+                        return null; // 后面需要过滤掉null
+                    }
+                    // 使用"-;-"分割,取第一个部分
+                    String[] parts = signature.split(FILE_SEPARATOR, 2); // 限制分割成2部分,这样性能更好,我们只需要第一部分
+                    return parts[0].trim(); // 取第一个部分并去除空格
+                }, Collectors.joining(","))));
+        // 甲方签名路径
+        String partAPath = "";
+        // 甲方签名日期
+        String partASignatureDate = "";
+        // 甲方名称
+        String partAName = "";
+        SimpleDateFormat sdf = new SimpleDateFormat(DATE_PATTERN_YMD_CN);
+        String partAIds = signatureDataMap.getOrDefault(PARTY_A, "");
+        if (StringUtils.isNotBlank(partAIds)) {
+            SysFileItemDo sysFileItemDo = sysFileItemServiceImpl.getById(partAIds);
+            partAPath = sysFileItemDo == null ? "" : sysFileItemDo.getFullpath();
+            partASignatureDate = sysFileItemDo == null ? "" : sdf.format(sysFileItemDo.getCreatedate());
+            partAName = sysFileItemDo == null ? "" : sysFileItemDo.getCreateusername();
+        }
+
+        String partBIds = signatureDataMap.getOrDefault(PARTY_B, "");
+        List<SysFileItemDo> partBPathList = new ArrayList<>();
+        if (StringUtils.isNotBlank(partAIds)) {
+            partBPathList = sysFileItemServiceImpl.getBaseMapper().selectBatchIds(Arrays.asList(partBIds.split(",")));
+        }
+
+        //需要填充word的模板数据
+        HashMap<String, String> wordMergeDataMap = new HashMap<>();
+        wordMergeDataMap.put("JFQM", partAPath);
+        wordMergeDataMap.put("JFRQ", partASignatureDate);
+
+        generateZip(partAPath, partBPathList, partAName, qhseTargetResponsibilityDocumentDo.getResponsibilitydocumentname(), tempFile.getFullpath(),
+                wordMergeDataMap, response, sdf);
 
+    }
 
+    /**
+     * 创建压缩包
+     */
+    public void generateZip(String partAPath, List<SysFileItemDo> partBPathList, String partAName, String docName, String tempPath,
+                            HashMap<String, String> wordMergeDataMap, HttpServletResponse response, SimpleDateFormat sdf) {
+        int value = Year.now().getValue();
+        String fileName = null;
+        try {
+            fileName = URLEncoder.encode(value + docName + ".zip", "utf-8");
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        response.setContentType("application/zip");
+        response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
+        String suffix = ".docx";
+        // 1.特殊处理当 只有甲方没有乙方时 需要生成一个附件 附件只有甲方签名
+        boolean onlyPartASignature = partBPathList.isEmpty() && StringUtils.isNotBlank(partAPath);
+
+        // 2. 预加载模板到内存(避免重复IO)
+        byte[] templateBytes;
+        try {
+            templateBytes = Files.readAllBytes(Paths.get(tempPath));
+        } catch (IOException e) {
+            log.error("模板文件读取失败: {}", tempPath, e);
+            throw new CustomException("模板文件加载失败");
+        }
+
+
+        try (OutputStream out = response.getOutputStream();
+             ZipOutputStream outputStreamZip = new ZipOutputStream(out);
+             ByteArrayInputStream bis = new ByteArrayInputStream(templateBytes);) {
+            // 创建临时文件
+            // File tempZipFile = File.createTempFile("temp_" + now + "_" + new Random().nextInt(100), ".zip");
+            // 之前填充文件内容
+            Document doc;
+            if (onlyPartASignature) {
+                // 创建doc
+                doc = createDocument(templateBytes, wordMergeDataMap);
+                addDocumentToZip(outputStreamZip, doc, docName + partAName + suffix);
+                outputStreamZip.finish();
+                return;
+            } else {
+                for (SysFileItemDo sysFileItemDo : partBPathList) {
+                    wordMergeDataMap.put("YFQM", sysFileItemDo.getFullpath());
+                    wordMergeDataMap.put("YFRQ", sdf.format(sysFileItemDo.getCreatedate()));
+                    doc = createDocument(templateBytes, wordMergeDataMap);
+                    addDocumentToZip(outputStreamZip, doc, docName + partAName + sysFileItemDo.getCreateusername() + suffix);
+                }
+                outputStreamZip.finish();
+            }
+        } catch (Exception e) {
+            log.error("责任书压缩包生成失败- 原因: {} | 异常类型: {}", e.getMessage(), e.getClass().getSimpleName(), e);
+            throw new CustomException("文件生成失败,请联系系统管理员!");
+        }
+    }
+
+    // 将文档添加到ZIP压缩包
+    private void addDocumentToZip(ZipOutputStream zos, Document doc, String fileName) throws Exception {
+        // 创建ZIP条目
+        ZipEntry entry = new ZipEntry(fileName);
+        zos.putNextEntry(entry);
+        // 将Word文档写入ZIP
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        doc.save(baos, SaveFormat.DOCX);
+        baos.writeTo(zos);
+        zos.closeEntry();
+    }
+
+    // 抽取文档创建方法
+    private Document createDocument(byte[] templateBytes, Map<String, String> data) throws Exception {
+        try (ByteArrayInputStream bis = new ByteArrayInputStream(templateBytes)) {
+            Document doc = new Document(bis);
+            doc.getMailMerge().setFieldMergingCallback(new WordMergeHandler());
+            WordUtils.MailMergeFill(data, doc);
+            return doc;
+        }
+    }
+}
 

+ 13 - 0
qhse-common/src/main/java/com/rongwei/bscommon/sys/utils/QHSEConstant.java

@@ -33,7 +33,20 @@ public class QHSEConstant {
         public static final String XLS = "xls";
         public static final String XLSX = "xlsx";
         public static final String PDF = "pdf";
+        public static final String PNG = "png";
+        public static final String JPEG = "jpeg";
+        public static final String JPG = "jpg";
     }
 
+    public static class ContentType {
+
+        public static final String STREAM = " application/octet-stream";
+        public static final String ZIP = " application/zip";
+        public static final String PDF="application/pdf";
+        public static final String PNG = "image/png";
+        public static final String JPG = "image/jpeg";
+
+    }
+    public static final String DEFAULT_WATER_MARK="ZPMC-NT-%s-%s";
 }
 

+ 15 - 3
qhse-server/src/main/java/com/rongwei/controller/FileFormatConversionController.java

@@ -7,7 +7,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletResponse;
-import java.util.Map;
 
 /**
  * FileFormatConversionController class
@@ -29,9 +28,22 @@ public class FileFormatConversionController {
      * @param id
      * @param response
      */
-    @PostMapping("/format/conversion/{id}")
+    @GetMapping("/format/conversion/{id}")
     public void fileFormatConversion(@PathVariable String id, HttpServletResponse response) {
         log.info("文件预览接口入参为:{}", id);
-        fileFormatConversionService.fileFormatConversion(id, response);
+        fileFormatConversionService.fileFormatConversion(id, response,false);
     }
+
+    /**
+     * 文件转为pdf 预览带水印
+     *
+     * @param id
+     * @param response
+     */
+    @GetMapping("/preview/waterMark/{id}")
+    public void fileFormatConversionAndWaterMark(@PathVariable String id, HttpServletResponse response) {
+        log.info("文件预览接口入参为:{}", id);
+        fileFormatConversionService.fileFormatConversion(id, response,true);
+    }
+
 }

+ 14 - 1
qhse-server/src/main/java/com/rongwei/controller/LettersOfResponsibilityController.java

@@ -23,12 +23,25 @@ public class LettersOfResponsibilityController {
     private QhseTargetResponsibilityDocumentServiceImpl qhseTargetResponsibilityDocumentService;
 
     /**
+     * 签名文件预览
      * @param id
      * @param response
      */
-    @PostMapping("/signature/preview")
+    @GetMapping("/signature/preview")
     public void lettersOfResponsibilitySignaturePreview(@RequestBody Map<String, String> mapData, HttpServletResponse response) {
         log.info("增加签名接口入参为:{}", mapData);
         qhseTargetResponsibilityDocumentService.lettersOfResponsibilitySignaturePreview(mapData, response);
     }
+
+
+    /**
+     * 责任书压缩包下载
+     * @param id
+     * @param response
+     */
+    @PostMapping("/zip/download/{id}")
+    public void zipDownload(@PathVariable String id, HttpServletResponse response) {
+        log.info("责任书下载接口入参为:{}", id);
+        qhseTargetResponsibilityDocumentService.zipDownload(id, response);
+    }
 }