|
@@ -822,7 +822,8 @@ public class AsyncMaterialSummaryService {
|
|
|
*/
|
|
*/
|
|
|
@Async
|
|
@Async
|
|
|
public void generateWordArchiveAsync(String taskId) {
|
|
public void generateWordArchiveAsync(String taskId) {
|
|
|
- CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
|
|
|
|
+ boolean success = false;
|
|
|
|
|
+ String archiveUrl = null;
|
|
|
try {
|
|
try {
|
|
|
logger.info("开始生成Word卷宗,任务ID:{}", taskId);
|
|
logger.info("开始生成Word卷宗,任务ID:{}", taskId);
|
|
|
|
|
|
|
@@ -835,11 +836,9 @@ public class AsyncMaterialSummaryService {
|
|
|
boolean isFirstDocument = true;
|
|
boolean isFirstDocument = true;
|
|
|
|
|
|
|
|
// 按顺序合并:封面(-1) -> 目录(-2) -> 14个资料(1-13) -> 封底(-3)
|
|
// 按顺序合并:封面(-1) -> 目录(-2) -> 14个资料(1-13) -> 封底(-3)
|
|
|
- // 排序:-1, -2, 1, 2, ..., 13, -3
|
|
|
|
|
allSummaryList.sort((a, b) -> {
|
|
allSummaryList.sort((a, b) -> {
|
|
|
int orderA = a.getMaterialOrderNum() != null ? a.getMaterialOrderNum() : 0;
|
|
int orderA = a.getMaterialOrderNum() != null ? a.getMaterialOrderNum() : 0;
|
|
|
int orderB = b.getMaterialOrderNum() != null ? b.getMaterialOrderNum() : 0;
|
|
int orderB = b.getMaterialOrderNum() != null ? b.getMaterialOrderNum() : 0;
|
|
|
- // -1(封面) < -2(目录) < 1-13(资料) < -3(封底)
|
|
|
|
|
int sortA = orderA == -1 ? -100 : (orderA == -2 ? -99 : (orderA == -3 ? 100 : orderA));
|
|
int sortA = orderA == -1 ? -100 : (orderA == -2 ? -99 : (orderA == -3 ? 100 : orderA));
|
|
|
int sortB = orderB == -1 ? -100 : (orderB == -2 ? -99 : (orderB == -3 ? 100 : orderB));
|
|
int sortB = orderB == -1 ? -100 : (orderB == -2 ? -99 : (orderB == -3 ? 100 : orderB));
|
|
|
return Integer.compare(sortA, sortB);
|
|
return Integer.compare(sortA, sortB);
|
|
@@ -877,26 +876,62 @@ public class AsyncMaterialSummaryService {
|
|
|
document.close();
|
|
document.close();
|
|
|
|
|
|
|
|
// 生成访问URL
|
|
// 生成访问URL
|
|
|
- String archiveUrl = FileUploadUtil.getPathFileName(outputPath, fileName);
|
|
|
|
|
-
|
|
|
|
|
|
|
+ archiveUrl = FileUploadUtil.getPathFileName(outputPath, fileName);
|
|
|
|
|
+ success = true;
|
|
|
logger.info("Word卷宗生成完成,任务ID:{},URL:{}", taskId, archiveUrl);
|
|
logger.info("Word卷宗生成完成,任务ID:{},URL:{}", taskId, archiveUrl);
|
|
|
|
|
|
|
|
- // 更新任务的卷宗URL
|
|
|
|
|
- if (task != null) {
|
|
|
|
|
- task.setArchiveUrl(archiveUrl);
|
|
|
|
|
- task.setArchiveStatus("2");
|
|
|
|
|
- task.setArchiveTime(LocalDateTime.now());
|
|
|
|
|
- costProjectTaskManager.updateById(task);
|
|
|
|
|
- logger.info("卷宗URL已更新,任务ID:{}", taskId);
|
|
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("生成Word卷宗失败,任务ID:{},错误:{}", taskId, e.getMessage(), e);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ // 无论成功失败,都更新状态
|
|
|
|
|
+ try {
|
|
|
|
|
+ CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
|
|
+ if (task != null) {
|
|
|
|
|
+ if (success) {
|
|
|
|
|
+ task.setArchiveUrl(archiveUrl);
|
|
|
|
|
+ task.setArchiveStatus("2");
|
|
|
|
|
+ task.setArchiveTime(LocalDateTime.now());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ task.setArchiveStatus("3");
|
|
|
|
|
+ }
|
|
|
|
|
+ costProjectTaskManager.updateById(task);
|
|
|
|
|
+ logger.info("卷宗状态已更新,任务ID:{},状态:{}", taskId, success ? "2-成功" : "3-失败");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("更新卷宗状态失败,任务ID:{},错误:{}", taskId, e.getMessage(), e);
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- if (task != null) {
|
|
|
|
|
- task.setArchiveStatus("3");
|
|
|
|
|
- costProjectTaskManager.updateById(task);
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将URL转换为本地文件路径
|
|
|
|
|
+ * 支持格式:
|
|
|
|
|
+ * 1. /profile/upload/xxx.docx
|
|
|
|
|
+ * 2. http://xxx/profile/upload/xxx.docx
|
|
|
|
|
+ * 3. 本地绝对路径
|
|
|
|
|
+ */
|
|
|
|
|
+ private String convertToLocalPath(String fileUrl) {
|
|
|
|
|
+ if (StringUtil.isEmpty(fileUrl)) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // http或https开头,提取/profile部分
|
|
|
|
|
+ if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) {
|
|
|
|
|
+ int profileIndex = fileUrl.indexOf("/profile/");
|
|
|
|
|
+ if (profileIndex > 0) {
|
|
|
|
|
+ String relativePath = fileUrl.substring(profileIndex);
|
|
|
|
|
+ return EipConfig.getProfile() + relativePath.substring(8);
|
|
|
}
|
|
}
|
|
|
- logger.error("生成Word卷宗失败,任务ID:,错误:{}", taskId, e.getMessage(), e);
|
|
|
|
|
|
|
+ return null;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // /profile开头
|
|
|
|
|
+ if (fileUrl.startsWith("/profile")) {
|
|
|
|
|
+ return EipConfig.getProfile() + fileUrl.substring(8);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 本地绝对路径
|
|
|
|
|
+ return fileUrl;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -909,10 +944,10 @@ public class AsyncMaterialSummaryService {
|
|
|
*/
|
|
*/
|
|
|
private boolean mergeDocumentFile(XWPFDocument document, String fileUrl, boolean isFirstDocument) {
|
|
private boolean mergeDocumentFile(XWPFDocument document, String fileUrl, boolean isFirstDocument) {
|
|
|
try {
|
|
try {
|
|
|
- String filePath = fileUrl;
|
|
|
|
|
- // 处理路径:/profile 开头的路径需要替换为实际路径
|
|
|
|
|
- if (filePath.startsWith("/profile")) {
|
|
|
|
|
- filePath = EipConfig.getProfile() + filePath.substring(8);
|
|
|
|
|
|
|
+ String filePath = convertToLocalPath(fileUrl);
|
|
|
|
|
+ if (filePath == null) {
|
|
|
|
|
+ logger.warn("无法解析文件路径:{}", fileUrl);
|
|
|
|
|
+ return isFirstDocument;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
java.io.File file = new java.io.File(filePath);
|
|
java.io.File file = new java.io.File(filePath);
|
|
@@ -953,36 +988,51 @@ public class AsyncMaterialSummaryService {
|
|
|
/**
|
|
/**
|
|
|
* 合并Word文档
|
|
* 合并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());
|
|
|
|
|
|
|
+ private void mergeWordDocument(XWPFDocument document, String filePath) {
|
|
|
|
|
+ java.io.FileInputStream fis = null;
|
|
|
|
|
+ XWPFDocument sourceDoc = null;
|
|
|
|
|
+ try {
|
|
|
|
|
+ fis = new java.io.FileInputStream(filePath);
|
|
|
|
|
+ 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());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.error("合并Word失败:{},错误:{}", filePath, e.getMessage());
|
|
|
|
|
+ XWPFParagraph para = document.createParagraph();
|
|
|
|
|
+ XWPFRun run = para.createRun();
|
|
|
|
|
+ run.setText("[Word文件:" + new java.io.File(filePath).getName() + " - 无法嵌入]");
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (sourceDoc != null) sourceDoc.close();
|
|
|
|
|
+ if (fis != null) fis.close();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.warn("关闭文件流失败:{}", e.getMessage());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- sourceDoc.close();
|
|
|
|
|
- fis.close();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 合并PDF文档(转换为图片后插入)
|
|
* 合并PDF文档(转换为图片后插入)
|
|
|
*/
|
|
*/
|
|
|
- private void mergePdfDocument(XWPFDocument document, String filePath) throws Exception {
|
|
|
|
|
|
|
+ private void mergePdfDocument(XWPFDocument document, String filePath) {
|
|
|
|
|
+ PDDocument pdfDoc = null;
|
|
|
try {
|
|
try {
|
|
|
- PDDocument pdfDoc = PDDocument.load(new java.io.File(filePath));
|
|
|
|
|
|
|
+ pdfDoc = PDDocument.load(new java.io.File(filePath));
|
|
|
org.apache.pdfbox.rendering.PDFRenderer renderer = new org.apache.pdfbox.rendering.PDFRenderer(pdfDoc);
|
|
org.apache.pdfbox.rendering.PDFRenderer renderer = new org.apache.pdfbox.rendering.PDFRenderer(pdfDoc);
|
|
|
|
|
+ int pageCount = pdfDoc.getNumberOfPages();
|
|
|
|
|
|
|
|
- for (int i = 0; i < pdfDoc.getNumberOfPages(); i++) {
|
|
|
|
|
|
|
+ for (int i = 0; i < pageCount; i++) {
|
|
|
java.awt.image.BufferedImage image = renderer.renderImageWithDPI(i, 200);
|
|
java.awt.image.BufferedImage image = renderer.renderImageWithDPI(i, 200);
|
|
|
|
|
|
|
|
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
|
|
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
|
|
@@ -999,29 +1049,34 @@ public class AsyncMaterialSummaryService {
|
|
|
|
|
|
|
|
para.createRun().addBreak();
|
|
para.createRun().addBreak();
|
|
|
|
|
|
|
|
- if (i < pdfDoc.getNumberOfPages() - 1) {
|
|
|
|
|
|
|
+ if (i < pageCount - 1) {
|
|
|
XWPFParagraph pageBreak = document.createParagraph();
|
|
XWPFParagraph pageBreak = document.createParagraph();
|
|
|
XWPFRun pageBreakRun = pageBreak.createRun();
|
|
XWPFRun pageBreakRun = pageBreak.createRun();
|
|
|
pageBreakRun.addBreak(BreakType.PAGE);
|
|
pageBreakRun.addBreak(BreakType.PAGE);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- pdfDoc.close();
|
|
|
|
|
logger.info("PDF文件已合并:{}", filePath);
|
|
logger.info("PDF文件已合并:{}", filePath);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
logger.error("合并PDF失败:{},错误:{}", filePath, e.getMessage());
|
|
logger.error("合并PDF失败:{},错误:{}", filePath, e.getMessage());
|
|
|
XWPFParagraph para = document.createParagraph();
|
|
XWPFParagraph para = document.createParagraph();
|
|
|
XWPFRun run = para.createRun();
|
|
XWPFRun run = para.createRun();
|
|
|
run.setText("[PDF文件:" + new java.io.File(filePath).getName() + " - 无法嵌入]");
|
|
run.setText("[PDF文件:" + new java.io.File(filePath).getName() + " - 无法嵌入]");
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (pdfDoc != null) pdfDoc.close();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.warn("关闭PDDocument失败:{}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 合并Excel文档(转换为表格后插入)
|
|
* 合并Excel文档(转换为表格后插入)
|
|
|
*/
|
|
*/
|
|
|
- private void mergeExcelDocument(XWPFDocument document, String filePath) throws Exception {
|
|
|
|
|
|
|
+ private void mergeExcelDocument(XWPFDocument document, String filePath) {
|
|
|
|
|
+ org.apache.poi.ss.usermodel.Workbook workbook = null;
|
|
|
try {
|
|
try {
|
|
|
- org.apache.poi.ss.usermodel.Workbook workbook = org.apache.poi.ss.usermodel.WorkbookFactory.create(new java.io.File(filePath));
|
|
|
|
|
|
|
+ workbook = org.apache.poi.ss.usermodel.WorkbookFactory.create(new java.io.File(filePath));
|
|
|
|
|
|
|
|
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
|
|
for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) {
|
|
|
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(sheetIndex);
|
|
org.apache.poi.ss.usermodel.Sheet sheet = workbook.getSheetAt(sheetIndex);
|
|
@@ -1063,14 +1118,18 @@ public class AsyncMaterialSummaryService {
|
|
|
pageBreakRun.addBreak(BreakType.PAGE);
|
|
pageBreakRun.addBreak(BreakType.PAGE);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- workbook.close();
|
|
|
|
|
logger.info("Excel文件已合并:{}", filePath);
|
|
logger.info("Excel文件已合并:{}", filePath);
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
logger.error("合并Excel失败:{},错误:{}", filePath, e.getMessage());
|
|
logger.error("合并Excel失败:{},错误:{}", filePath, e.getMessage());
|
|
|
XWPFParagraph para = document.createParagraph();
|
|
XWPFParagraph para = document.createParagraph();
|
|
|
XWPFRun run = para.createRun();
|
|
XWPFRun run = para.createRun();
|
|
|
- run.setText("[Excel文件:" + new java.io.File(filePath).getName() + " - 无法嵌入,请查看原文件]");
|
|
|
|
|
|
|
+ run.setText("[Excel文件:" + new java.io.File(filePath).getName() + " - 无法嵌入]");
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (workbook != null) workbook.close();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.warn("关闭Workbook失败:{}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1359,7 +1418,7 @@ public class AsyncMaterialSummaryService {
|
|
|
CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
|
|
CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
|
|
|
if (task != null) {
|
|
if (task != null) {
|
|
|
task.setArchiveNo(req.getArchiveNo());
|
|
task.setArchiveNo(req.getArchiveNo());
|
|
|
- task.setArchiveUser(ContextUtil.getCurrentUser().getAccount());
|
|
|
|
|
|
|
+ task.setArchiveUser(ContextUtil.getCurrentUser().getFullname());
|
|
|
costProjectTaskManager.updateById(task);
|
|
costProjectTaskManager.updateById(task);
|
|
|
}
|
|
}
|
|
|
|
|
|