Selaa lähdekoodia

fix:卷宗合并

zzw 1 viikko sitten
vanhempi
commit
deeae588a1

+ 17 - 0
assistMg/pom.xml

@@ -65,6 +65,23 @@
             <scope>compile</scope>
         </dependency>
 
+        <!-- PDF处理 -->
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>pdfbox</artifactId>
+            <version>2.0.28</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.pdfbox</groupId>
+                    <artifactId>fontbox</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.pdfbox</groupId>
+            <artifactId>fontbox</artifactId>
+            <version>2.0.28</version>
+        </dependency>
 
     </dependencies>
     <!-- 用于生成jar文件-->

+ 26 - 2
assistMg/src/main/java/com/hotent/enterpriseDeclare/controller/material/CostProjectTaskSurveyGenericController.java

@@ -8,8 +8,9 @@ import com.hotent.base.constants.ApiGroupConsts;
 import com.hotent.base.model.CommonResult;
 import com.hotent.base.util.StringUtil;
 import com.hotent.baseInfo.manager.CostCatalogSurveyManager;
-import com.hotent.baseInfo.manager.CostCatalogUnitManager;
 import com.hotent.baseInfo.model.CostCatalogSurvey;
+import com.hotent.baseInfo.vo.FileUploadResult;
+import com.hotent.config.EipConfig;
 import com.hotent.enterpriseDeclare.manager.CostAuditPeriodRecordManager;
 import com.hotent.enterpriseDeclare.manager.CostSurveyTemplateUploadDataManager;
 import com.hotent.enterpriseDeclare.model.CostAuditPeriodRecord;
@@ -32,6 +33,7 @@ import com.hotent.sys.persistence.manager.DataDictManager;
 import com.hotent.sys.persistence.manager.SysTypeManager;
 import com.hotent.sys.persistence.model.DataDict;
 import com.hotent.sys.persistence.model.SysType;
+import com.hotent.util.FileUploadUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
@@ -1456,10 +1458,16 @@ public class CostProjectTaskSurveyGenericController {
                     }
                     costSurveyTemplateUploadDataManager.saveData(dataList);
 
-                    // 更新上传状态
+                    // 更新上传状态和文件URL
                     CostSurveyTemplateUpload upload = costSurveyTemplateUploadManager.getById(refId);
                     if (upload != null) {
                         upload.setIsUpload("1");
+                        // 保存文件并获取URL
+                        String fileUrl = saveUploadedFile(file);
+                        if (StringUtil.isNotEmpty(fileUrl)) {
+                            upload.setFileUrl(fileUrl);
+                        }
+                        upload.setUploadTime(LocalDateTime.now());
                         costSurveyTemplateUploadManager.updateById(upload);
                     }
 
@@ -1695,6 +1703,12 @@ public class CostProjectTaskSurveyGenericController {
                         CostProjectTaskMaterial material = costProjectTaskMaterialManager.getById(materialId);
                         if (material != null) {
                             material.setIsUpload("1");
+                            // 保存文件并获取URL
+                            String fileUrl = saveUploadedFile(file);
+                            if (StringUtil.isNotEmpty(fileUrl)) {
+                                material.setFileUrl(fileUrl);
+                            }
+                            material.setUploadTime(LocalDateTime.now());
                             costProjectTaskMaterialManager.updateById(material);
                         }
                     }
@@ -1880,6 +1894,16 @@ public class CostProjectTaskSurveyGenericController {
         }
     }
 
+    /**
+     * 保存上传的文件并返回URL
+     */
+    private String saveUploadedFile(MultipartFile file) throws Exception {
+        FileUploadResult result = FileUploadUtil.uploadFile(file, EipConfig.getUploadPath());
+        if (result != null && result.getSavePath() != null) {
+            return EipConfig.getImgUrl() + result.getSavePath();
+        }
+        return null;
+    }
 
     /**
      * 计算核定表的 orderNum(根据模板的排序规则)

+ 155 - 36
assistMg/src/main/java/com/hotent/project/service/AsyncMaterialSummaryService.java

@@ -16,6 +16,7 @@ import com.hotent.uc.util.ContextUtil;
 import com.hotent.util.FileUploadUtil;
 import com.hotent.util.wordexcelutils.CompleteTemplateProcessor;
 import com.hotent.util.wordexcelutils.SmartTemplateWriter;
+import org.apache.pdfbox.pdmodel.PDDocument;
 import org.apache.poi.xwpf.usermodel.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -899,7 +900,7 @@ public class AsyncMaterialSummaryService {
     }
 
     /**
-     * 合并单个文档文件到主文档(保持原始样式)
+     * 合并单个文档文件到主文档(支持Word、PDF、Excel等多种格式)
      *
      * @param document        主文档
      * @param fileUrl         文件URL(如:/profile/upload/20251116/xxx.docx)
@@ -920,6 +921,8 @@ public class AsyncMaterialSummaryService {
                 return isFirstDocument;
             }
 
+            String lowerCasePath = filePath.toLowerCase();
+
             // 添加分页符(非第一个文档)
             if (!isFirstDocument) {
                 XWPFParagraph pageBreakPara = document.createParagraph();
@@ -927,30 +930,18 @@ public class AsyncMaterialSummaryService {
                 pageBreakRun.addBreak(BreakType.PAGE);
             }
 
-            // 读取Word文件
-            java.io.FileInputStream fis = new java.io.FileInputStream(filePath);
-            XWPFDocument sourceDoc = new XWPFDocument(fis);
-
-            // 使用XML级别复制,保持原始样式
-            org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody srcBody = sourceDoc.getDocument().getBody();
-            org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody destBody = document.getDocument().getBody();
-
-            // 复制所有元素(段落、表格等)
-            for (org.apache.xmlbeans.XmlObject obj : srcBody.selectPath("./*")) {
-                if (obj instanceof org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP) {
-                    // 复制段落
-                    org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP newP = destBody.addNewP();
-                    newP.set(obj.copy());
-                } else if (obj instanceof org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl) {
-                    // 复制表格
-                    org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl newTbl = destBody.addNewTbl();
-                    newTbl.set(obj.copy());
-                }
+            // 根据文件类型处理
+            if (lowerCasePath.endsWith(".docx") || lowerCasePath.endsWith(".doc")) {
+                mergeWordDocument(document, filePath);
+            } else if (lowerCasePath.endsWith(".pdf")) {
+                mergePdfDocument(document, filePath);
+            } else if (lowerCasePath.endsWith(".xlsx") || lowerCasePath.endsWith(".xls")) {
+                mergeExcelDocument(document, filePath);
+            } else {
+                logger.warn("不支持的文件格式:{}", fileUrl);
+                return isFirstDocument;
             }
 
-            sourceDoc.close();
-            fis.close();
-
             return false;
 
         } catch (Exception e) {
@@ -960,6 +951,130 @@ public class AsyncMaterialSummaryService {
     }
 
     /**
+     * 合并Word文档
+     */
+    private void mergeWordDocument(XWPFDocument document, String filePath) throws Exception {
+        java.io.FileInputStream fis = new java.io.FileInputStream(filePath);
+        XWPFDocument sourceDoc = new XWPFDocument(fis);
+
+        org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody srcBody = sourceDoc.getDocument().getBody();
+        org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBody destBody = document.getDocument().getBody();
+
+        for (org.apache.xmlbeans.XmlObject obj : srcBody.selectPath("./*")) {
+            if (obj instanceof org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP) {
+                org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP newP = destBody.addNewP();
+                newP.set(obj.copy());
+            } else if (obj instanceof org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl) {
+                org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl newTbl = destBody.addNewTbl();
+                newTbl.set(obj.copy());
+            }
+        }
+
+        sourceDoc.close();
+        fis.close();
+    }
+
+    /**
+     * 合并PDF文档(转换为图片后插入)
+     */
+    private void mergePdfDocument(XWPFDocument document, String filePath) throws Exception {
+        try {
+            PDDocument pdfDoc = PDDocument.load(new java.io.File(filePath));
+            org.apache.pdfbox.rendering.PDFRenderer renderer = new org.apache.pdfbox.rendering.PDFRenderer(pdfDoc);
+
+            for (int i = 0; i < pdfDoc.getNumberOfPages(); i++) {
+                java.awt.image.BufferedImage image = renderer.renderImageWithDPI(i, 200);
+
+                java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
+                javax.imageio.ImageIO.write(image, "png", baos);
+                byte[] imageBytes = baos.toByteArray();
+                baos.close();
+
+                XWPFParagraph para = document.createParagraph();
+                XWPFRun run = para.createRun();
+                java.io.ByteArrayInputStream bais = new java.io.ByteArrayInputStream(imageBytes);
+                run.addPicture(bais, org.apache.poi.xwpf.usermodel.Document.PICTURE_TYPE_PNG,
+                        "pdf_page_" + i + ".png", org.apache.poi.util.Units.toEMU(410), org.apache.poi.util.Units.toEMU(600));
+                bais.close();
+
+                para.createRun().addBreak();
+
+                if (i < pdfDoc.getNumberOfPages() - 1) {
+                    XWPFParagraph pageBreak = document.createParagraph();
+                    XWPFRun pageBreakRun = pageBreak.createRun();
+                    pageBreakRun.addBreak(BreakType.PAGE);
+                }
+            }
+
+            pdfDoc.close();
+            logger.info("PDF文件已合并:{}", filePath);
+        } catch (Exception e) {
+            logger.error("合并PDF失败:{},错误:{}", filePath, e.getMessage());
+            XWPFParagraph para = document.createParagraph();
+            XWPFRun run = para.createRun();
+            run.setText("[PDF文件:" + new java.io.File(filePath).getName() + " - 无法嵌入]");
+        }
+    }
+
+    /**
+     * 合并Excel文档(转换为表格后插入)
+     */
+    private void mergeExcelDocument(XWPFDocument document, String filePath) throws Exception {
+        try {
+            org.apache.poi.ss.usermodel.Workbook workbook = org.apache.poi.ss.usermodel.WorkbookFactory.create(new java.io.File(filePath));
+
+            for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
+                org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(sheetIndex);
+
+                if (sheet.getPhysicalNumberOfRows() == 0) continue;
+
+                int rows = sheet.getPhysicalNumberOfRows();
+                int cols = 0;
+                for (int i = 0; i < rows; i++) {
+                    org.apache.poi.ss.usermodel.Row row = sheet.getRow(i);
+                    if (row != null && row.getPhysicalNumberOfCells() > cols) {
+                        cols = row.getPhysicalNumberOfCells();
+                    }
+                }
+
+                if (cols == 0) cols = 1;
+
+                XWPFTable table = document.createTable(rows, cols);
+                table.setStyleID("TableGrid");
+
+                for (int i = 0; i < rows; i++) {
+                    org.apache.poi.ss.usermodel.Row excelRow = sheet.getRow(i);
+                    XWPFTableRow wordRow = table.getRow(i);
+
+                    if (excelRow != null) {
+                        for (int j = 0; j < cols; j++) {
+                            org.apache.poi.ss.usermodel.Cell cell = excelRow.getCell(j);
+                            String cellValue = cell != null ? cell.toString() : "";
+
+                            XWPFTableCell wordCell = wordRow.getCell(j);
+                            wordCell.setText(cellValue);
+                        }
+                    }
+                }
+
+                if (sheetIndex < workbook.getNumberOfSheets() - 1) {
+                    XWPFParagraph pageBreak = document.createParagraph();
+                    XWPFRun pageBreakRun = pageBreak.createRun();
+                    pageBreakRun.addBreak(BreakType.PAGE);
+                }
+            }
+
+            workbook.close();
+            logger.info("Excel文件已合并:{}", filePath);
+        } catch (Exception e) {
+            logger.error("合并Excel失败:{},错误:{}", filePath, e.getMessage());
+            XWPFParagraph para = document.createParagraph();
+            XWPFRun run = para.createRun();
+            run.setText("[Excel文件:" + new java.io.File(filePath).getName() + " - 无法嵌入,请查看原文件]");
+        }
+    }
+
+    /**
      * 更新单个资料归纳主表的总页数
      *
      * @param masterId 主表ID
@@ -1054,23 +1169,17 @@ public class AsyncMaterialSummaryService {
                 return 0;
             }
 
-            // 判断文件类型
             String lowerCaseUrl = fileUrl.toLowerCase();
 
-            if (lowerCaseUrl.endsWith(".xls") || lowerCaseUrl.endsWith(".xlsx")) {
-                // Excel文件算1页
-                return 1;
-            } else if (lowerCaseUrl.endsWith(".doc") || lowerCaseUrl.endsWith(".docx")) {
-                // Word文件需要读取实际页数
+            if (lowerCaseUrl.endsWith(".doc") || lowerCaseUrl.endsWith(".docx")) {
                 return getWordPageCount(fileUrl);
             } else {
-                // 其他格式默认1页
                 return 1;
             }
 
         } catch (Exception e) {
             logger.error("计算文件页数失败,文件:{},错误:{}", fileUrl, e.getMessage(), e);
-            return 0;
+            return 1;
         }
     }
 
@@ -1093,17 +1202,27 @@ public class AsyncMaterialSummaryService {
             fis = new java.io.FileInputStream(filePath);
             document = new XWPFDocument(fis);
 
-            // 获取页数
-            int pageCount = document.getProperties().getExtendedProperties().getUnderlyingProperties().getPages();
+            // 获取页数(可能为null或0)
+            try {
+                int pageCount = document.getProperties().getExtendedProperties().getUnderlyingProperties().getPages();
+                if (pageCount > 0) {
+                    return pageCount;
+                }
+            } catch (Exception e) {
+                logger.debug("无法读取Word文档页数属性:{}", e.getMessage());
+            }
+
+            // 如果页数属性不可用,通过段落数估算(每页约50行)
+            int paragraphCount = document.getParagraphs().size();
+            int tableCount = document.getTables().size();
+            int estimatedPages = Math.max(1, (paragraphCount + tableCount * 10) / 50);
 
-            return pageCount > 0 ? pageCount : 1;
+            return estimatedPages;
 
         } catch (Exception e) {
             logger.error("读取Word页数失败,文件:{},错误:{}", fileUrl, e.getMessage(), e);
-            // 读取失败默认返回1页
             return 1;
         } finally {
-            // 关闭资源
             try {
                 if (document != null) {
                     document.close();