|
@@ -1,22 +1,31 @@
|
|
|
package com.hotent.project.service;
|
|
package com.hotent.project.service;
|
|
|
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
|
|
|
|
import com.hotent.base.util.StringUtil;
|
|
import com.hotent.base.util.StringUtil;
|
|
|
|
|
+import com.hotent.config.EipConfig;
|
|
|
import com.hotent.project.manager.*;
|
|
import com.hotent.project.manager.*;
|
|
|
import com.hotent.project.model.*;
|
|
import com.hotent.project.model.*;
|
|
|
import com.hotent.surveyinfo.manager.CostSurveyTemplateUploadManager;
|
|
import com.hotent.surveyinfo.manager.CostSurveyTemplateUploadManager;
|
|
|
import com.hotent.surveyinfo.model.CostSurveyTemplateUpload;
|
|
import com.hotent.surveyinfo.model.CostSurveyTemplateUpload;
|
|
|
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
|
|
|
|
-import org.apache.poi.xwpf.usermodel.XWPFParagraph;
|
|
|
|
|
-import org.apache.poi.xwpf.usermodel.XWPFRun;
|
|
|
|
|
|
|
+import com.hotent.uc.manager.OrgManager;
|
|
|
|
|
+import com.hotent.uc.manager.UserManager;
|
|
|
|
|
+import com.hotent.uc.model.Org;
|
|
|
|
|
+import com.hotent.uc.model.User;
|
|
|
|
|
+import com.hotent.util.FileUploadUtil;
|
|
|
|
|
+import com.hotent.util.wordexcelutils.CompleteTemplateProcessor;
|
|
|
|
|
+import com.hotent.util.wordexcelutils.SmartTemplateWriter;
|
|
|
|
|
+import org.apache.poi.xwpf.usermodel.*;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.scheduling.annotation.Async;
|
|
import org.springframework.scheduling.annotation.Async;
|
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
|
|
import java.io.FileOutputStream;
|
|
import java.io.FileOutputStream;
|
|
|
|
|
+import java.time.LocalDateTime;
|
|
|
import java.util.Comparator;
|
|
import java.util.Comparator;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -29,6 +38,8 @@ import java.util.stream.Collectors;
|
|
|
@Service
|
|
@Service
|
|
|
public class AsyncMaterialSummaryService {
|
|
public class AsyncMaterialSummaryService {
|
|
|
|
|
|
|
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(AsyncMaterialSummaryService.class);
|
|
|
|
|
+
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CostProjectTaskMaterialSummaryManager costProjectTaskMaterialSummaryManager;
|
|
private CostProjectTaskMaterialSummaryManager costProjectTaskMaterialSummaryManager;
|
|
|
|
|
|
|
@@ -44,7 +55,6 @@ public class AsyncMaterialSummaryService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager;
|
|
private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager;
|
|
|
|
|
|
|
|
-
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CostProjectTaskMaterialManager costProjectTaskMaterialManager;
|
|
private CostProjectTaskMaterialManager costProjectTaskMaterialManager;
|
|
|
|
|
|
|
@@ -54,25 +64,42 @@ public class AsyncMaterialSummaryService {
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CostProjectTaskAdjustmentRecordManager adjustmentRecordManager;
|
|
private CostProjectTaskAdjustmentRecordManager adjustmentRecordManager;
|
|
|
|
|
|
|
|
-
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CostProjectTaskEvidenceManager costProjectTaskEvidenceManager;
|
|
private CostProjectTaskEvidenceManager costProjectTaskEvidenceManager;
|
|
|
|
|
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private CostProjectTaskPreliminaryOpinionManager preliminaryOpinionManager;
|
|
private CostProjectTaskPreliminaryOpinionManager preliminaryOpinionManager;
|
|
|
|
|
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private CostProjectApprovalManager costProjectApprovalManager;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private OrgManager orgManager;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private UserManager userManager;
|
|
|
|
|
+
|
|
|
|
|
+ // 从配置文件读取模板路径
|
|
|
|
|
+ @org.springframework.beans.factory.annotation.Value("${archive.template.coverPath:}")
|
|
|
|
|
+ private String coverTemplatePath;
|
|
|
|
|
|
|
|
|
|
+ @org.springframework.beans.factory.annotation.Value("${archive.template.catalogPath:}")
|
|
|
|
|
+ private String catalogTemplatePath;
|
|
|
|
|
+
|
|
|
|
|
+ @org.springframework.beans.factory.annotation.Value("${archive.template.backCoverPath:}")
|
|
|
|
|
+ private String backCoverTemplatePath;
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 生成资料归纳主表(13个基础资料类别)- 核心逻辑
|
|
|
|
|
|
|
+ * 生成资料归纳主表(14个基础资料类别)- 核心逻辑
|
|
|
*
|
|
*
|
|
|
* @param mainTask 主任务
|
|
* @param mainTask 主任务
|
|
|
* @param childTasks 子任务列表
|
|
* @param childTasks 子任务列表
|
|
|
*/
|
|
*/
|
|
|
public void generateMaterialSummary(CostProjectTask mainTask, List<CostProjectTask> childTasks) {
|
|
public void generateMaterialSummary(CostProjectTask mainTask, List<CostProjectTask> childTasks) {
|
|
|
try {
|
|
try {
|
|
|
- // 定义13个基础资料类别
|
|
|
|
|
|
|
+ // 定义14个基础资料类别
|
|
|
String[] materialNames = {
|
|
String[] materialNames = {
|
|
|
"成本监审报告(含成本监审报告签发稿、送达回证)",
|
|
"成本监审报告(含成本监审报告签发稿、送达回证)",
|
|
|
"被监审单位申请定(调)价报告(复印件)",
|
|
"被监审单位申请定(调)价报告(复印件)",
|
|
@@ -86,10 +113,10 @@ public class AsyncMaterialSummaryService {
|
|
|
"成本监审集体审议记录",
|
|
"成本监审集体审议记录",
|
|
|
"成本监审工作底稿",
|
|
"成本监审工作底稿",
|
|
|
"成本监审提取资料登记表",
|
|
"成本监审提取资料登记表",
|
|
|
- "提取的成本资料和会计凭证等复印件"
|
|
|
|
|
|
|
+ "中止定价成本监审料通知书(含送达回证)"
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // 为主任务生成13个资料归纳主表记录
|
|
|
|
|
|
|
+ // 为主任务生成14个资料归纳主表记录
|
|
|
for (int i = 0; i < materialNames.length; i++) {
|
|
for (int i = 0; i < materialNames.length; i++) {
|
|
|
CostProjectTaskMaterialSummary summary = new CostProjectTaskMaterialSummary();
|
|
CostProjectTaskMaterialSummary summary = new CostProjectTaskMaterialSummary();
|
|
|
summary.setTaskId(mainTask.getId());
|
|
summary.setTaskId(mainTask.getId());
|
|
@@ -103,7 +130,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
// 记录异常日志,但不影响主流程
|
|
// 记录异常日志,但不影响主流程
|
|
|
- e.printStackTrace();
|
|
|
|
|
|
|
+ logger.error("生成资料归纳失败", e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -179,17 +206,21 @@ public class AsyncMaterialSummaryService {
|
|
|
// 提取的成本资料和会计凭证等复印件
|
|
// 提取的成本资料和会计凭证等复印件
|
|
|
generateType13Details(summary, mainTask, childTasks, documents);
|
|
generateType13Details(summary, mainTask, childTasks, documents);
|
|
|
break;
|
|
break;
|
|
|
|
|
+ case 14:
|
|
|
|
|
+ // 中止定价成本监审料通知书(含送达回证)
|
|
|
|
|
+ generateType14Details(summary, mainTask, childTasks, documents);
|
|
|
default:
|
|
default:
|
|
|
throw new RuntimeException("未知的资料类型");
|
|
throw new RuntimeException("未知的资料类型");
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- System.err.println("生成资料类型 " + materialType + " 的明细时出错:" + e.getMessage());
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
|
|
+ logger.error("生成资料类型 {} 的明细时出错:{}", materialType, e.getMessage(), e);
|
|
|
// 继续执行,不中断整个流程
|
|
// 继续执行,不中断整个流程
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型1:成本监审报告(含成本监审报告签发稿、送达回证) ====================
|
|
// ==================== 类型1:成本监审报告(含成本监审报告签发稿、送达回证) ====================
|
|
|
|
|
+ // A.成本监审报告(含成本监审报告签发稿)
|
|
|
|
|
+ // 包括成本监审报告、报告签发稿等文书。
|
|
|
private void generateType1Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectDocument> documents) {
|
|
private void generateType1Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本监审报告"、"成本监审报告签发稿"、"送达回证"
|
|
// 获取"成本监审报告"、"成本监审报告签发稿"、"送达回证"
|
|
@@ -215,6 +246,8 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型2:被监审单位申请定(调)价报告(复印件) ====================
|
|
// ==================== 类型2:被监审单位申请定(调)价报告(复印件) ====================
|
|
|
|
|
+ // 被监审单位申请定(调)价报告等。
|
|
|
|
|
+ //来源:从“监审立项”附件获取。
|
|
|
private void generateType2Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType2Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"申请定(调)价报告"
|
|
// 获取"申请定(调)价报告"
|
|
@@ -237,15 +270,32 @@ public class AsyncMaterialSummaryService {
|
|
|
detail.setIsDeleted("0");
|
|
detail.setIsDeleted("0");
|
|
|
costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
}
|
|
}
|
|
|
|
|
+ CostProjectApproval approval = costProjectApprovalManager.getById(mainTask.getProjectId());
|
|
|
|
|
+ if (approval != null && StringUtil.isNotEmpty(approval.getAccordingFileUrl())) {
|
|
|
|
|
+ CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail();
|
|
|
|
|
+ detail.setMasterId(summary.getId());
|
|
|
|
|
+ detail.setTaskId(mainTask.getId());
|
|
|
|
|
+ detail.setDocumentName("成本项目定(调)价依据");
|
|
|
|
|
+ detail.setDocumentNumber("");
|
|
|
|
|
+ detail.setAuditedUnitName("");
|
|
|
|
|
+ detail.setFileSource("系统生成电子文书");
|
|
|
|
|
+ detail.setPageCount(0);
|
|
|
|
|
+ detail.setAttachmentUrl(approval.getAccordingFileUrl());
|
|
|
|
|
+ detail.setOrderNum(orderNum++);
|
|
|
|
|
+ detail.setIsDeleted("0");
|
|
|
|
|
+ costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型3:成本监审通知书(含送达回证) ====================
|
|
// ==================== 类型3:成本监审通知书(含送达回证) ====================
|
|
|
|
|
+ // 包括成本监审通知书、送达回证等文书。
|
|
|
|
|
+ //来源:从“监审文书”中获取。
|
|
|
private void generateType3Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType3Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// "成本监审通知书"和"送达回证"
|
|
// "成本监审通知书"和"送达回证"
|
|
|
List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
|
.filter(doc -> "成本监审通知书".equals(doc.getDocumentName())
|
|
.filter(doc -> "成本监审通知书".equals(doc.getDocumentName())
|
|
|
- || "送达回证".equals(doc.getDocumentName()))
|
|
|
|
|
|
|
+ || "成本监审通知书-送达回证".equals(doc.getDocumentName()))
|
|
|
.sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
|
|
.sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
@@ -265,7 +315,9 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // ==================== 类型4:经营者需提供成本资料清单 ====================
|
|
|
|
|
|
|
+ // ==================== 类型4:经营者需提供成本资料清单(提取资料) ====================
|
|
|
|
|
+ // 成本监审任务中的资料报送要求。
|
|
|
|
|
+ //来源:从“监审任务部署”中获取。
|
|
|
private void generateType4Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType4Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本资料清单"
|
|
// 获取"成本资料清单"
|
|
@@ -288,9 +340,34 @@ public class AsyncMaterialSummaryService {
|
|
|
detail.setIsDeleted("0");
|
|
detail.setIsDeleted("0");
|
|
|
costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
}
|
|
}
|
|
|
|
|
+ for (CostProjectTask childTask : childTasks) {
|
|
|
|
|
+ List<CostProjectTaskEvidence> list = costProjectTaskEvidenceManager.list(
|
|
|
|
|
+ new LambdaQueryWrapper<CostProjectTaskEvidence>().eq(CostProjectTaskEvidence::getTaskId, childTask.getId())
|
|
|
|
|
+ );
|
|
|
|
|
+ for (CostProjectTaskEvidence evidence : list) {
|
|
|
|
|
+ // 只处理有附件的资料登记
|
|
|
|
|
+ if (StringUtil.isNotEmpty(evidence.getAttachmentUrl())) {
|
|
|
|
|
+ CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail();
|
|
|
|
|
+ detail.setMasterId(summary.getId());
|
|
|
|
|
+ detail.setTaskId(mainTask.getId());
|
|
|
|
|
+ detail.setDocumentName(evidence.getMaterialName() != null ? evidence.getMaterialName() : "提取资料登记");
|
|
|
|
|
+ detail.setDocumentNumber("");
|
|
|
|
|
+ detail.setAuditedUnitName(childTask.getAuditedUnitName() != null ? childTask.getAuditedUnitName() : "");
|
|
|
|
|
+ detail.setFileSource("系统生成电子文书");
|
|
|
|
|
+ detail.setPageCount(evidence.getPageCount() != null ? evidence.getPageCount() : 0);
|
|
|
|
|
+ detail.setAttachmentUrl(evidence.getAttachmentUrl());
|
|
|
|
|
+ detail.setOrderNum(orderNum++);
|
|
|
|
|
+ detail.setIsDeleted("0");
|
|
|
|
|
+ costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型5:《政府定价成本监审调查表》 ====================
|
|
// ==================== 类型5:《政府定价成本监审调查表》 ====================
|
|
|
|
|
+ // 各被监审单位的“成本监审调查表”文档。
|
|
|
|
|
+ //来源:从“监审任务”中获取各被监审单位填报的成本监审调查表。
|
|
|
private void generateType5Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType5Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
for (CostProjectTask childTask : childTasks) {
|
|
for (CostProjectTask childTask : childTasks) {
|
|
@@ -312,9 +389,12 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // 成本调查表(kkkk)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型6:成本监审补充资料通知书(含送达回证) ====================
|
|
// ==================== 类型6:成本监审补充资料通知书(含送达回证) ====================
|
|
|
|
|
+ // 监审主体发送给各被监审单位的补充资料通知书、送达回证等文书。
|
|
|
|
|
+ //来源:从“监审文书”中获取。
|
|
|
private void generateType6Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType6Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
@@ -362,12 +442,14 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型7:成本审核初步意见告知书(含送达回证) ====================
|
|
// ==================== 类型7:成本审核初步意见告知书(含送达回证) ====================
|
|
|
|
|
+ // 监审主体发送给各被监审单位的初步意见告知书、送达回证等文书。
|
|
|
|
|
+ // 来源:从“监审文书”中获取。
|
|
|
private void generateType7Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType7Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本审核初步意见告知书"和"送达回证"
|
|
// 获取"成本审核初步意见告知书"和"送达回证"
|
|
|
List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
|
.filter(doc -> "成本审核初步意见告知书".equals(doc.getDocumentName())
|
|
.filter(doc -> "成本审核初步意见告知书".equals(doc.getDocumentName())
|
|
|
- || "送达回证".equals(doc.getDocumentName()))
|
|
|
|
|
|
|
+ || "成本审核初步意见告知书-送达回证".equals(doc.getDocumentName()))
|
|
|
.sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
|
|
.sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
|
|
|
.collect(Collectors.toList());
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
@@ -388,6 +470,8 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型8:经营者书面反馈的材料 ====================
|
|
// ==================== 类型8:经营者书面反馈的材料 ====================
|
|
|
|
|
+ // 各被监审单位对初步意见告知书的意见反馈资料。
|
|
|
|
|
+ //来源:从“监审任务”中获取反馈意见。
|
|
|
private void generateType8Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType8Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"书面反馈材料"(来源:监审单位反馈文件)
|
|
// 获取"书面反馈材料"(来源:监审单位反馈文件)
|
|
@@ -437,6 +521,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型9:成本审核初步意见表(集体审议用) ====================
|
|
// ==================== 类型9:成本审核初步意见表(集体审议用) ====================
|
|
|
|
|
+ // 来源:从“监审文书”中获取
|
|
|
private void generateType9Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType9Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本审核初步意见表"
|
|
// 获取"成本审核初步意见表"
|
|
@@ -462,6 +547,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型10:成本监审集体审议记录 ====================
|
|
// ==================== 类型10:成本监审集体审议记录 ====================
|
|
|
|
|
+ // 来源:从“监审文书”中获取。
|
|
|
private void generateType10Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectDocument> documents) {
|
|
private void generateType10Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本监审集体审议记录"
|
|
// 获取"成本监审集体审议记录"
|
|
@@ -508,6 +594,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型11:成本监审工作底稿 ====================
|
|
// ==================== 类型11:成本监审工作底稿 ====================
|
|
|
|
|
+ // 来源:从“监审文书”中获取。
|
|
|
private void generateType11Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType11Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本监审工作底稿"
|
|
// 获取"成本监审工作底稿"
|
|
@@ -554,6 +641,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型12:成本监审提取资料登记表 ====================
|
|
// ==================== 类型12:成本监审提取资料登记表 ====================
|
|
|
|
|
+ // 来源:从“监审文书”中获取。
|
|
|
private void generateType12Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType12Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本监审提取资料登记表"
|
|
// 获取"成本监审提取资料登记表"
|
|
@@ -602,6 +690,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 类型13:提取的成本资料和会计凭证等复印件 ====================
|
|
// ==================== 类型13:提取的成本资料和会计凭证等复印件 ====================
|
|
|
|
|
+ // 来源:各被监审单位首次及补充材料时提交的资料,包括综合性材料、财会资料等。
|
|
|
private void generateType13Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
private void generateType13Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
int orderNum = 1;
|
|
int orderNum = 1;
|
|
|
// 获取"成本资料和会计凭证"(来源:被监审单位提交的资料)
|
|
// 获取"成本资料和会计凭证"(来源:被监审单位提交的资料)
|
|
@@ -626,109 +715,176 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // ==================== 类型14:中止定价成本监审料通知书(含送达回证) ====================
|
|
|
|
|
+ // 来源:从“监审文书”中获取。
|
|
|
|
|
+ private void generateType14Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List<CostProjectTask> childTasks, List<CostProjectDocument> documents) {
|
|
|
|
|
+ int orderNum = 1;
|
|
|
|
|
+ // 获取"成本资料和会计凭证"(来源:被监审单位提交的资料)
|
|
|
|
|
+ List<CostProjectDocument> matchedDocuments = documents.stream()
|
|
|
|
|
+ .filter(doc -> "中止定价成本监审通知书".equals(doc.getDocumentName())
|
|
|
|
|
+ || "中止定价成本监审通知书-送达回证".equals(doc.getDocumentName()))
|
|
|
|
|
+ .sorted(Comparator.comparing(doc -> doc.getOrderNum() != null ? doc.getOrderNum() : 0))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ for (CostProjectDocument document : matchedDocuments) {
|
|
|
|
|
+ CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail();
|
|
|
|
|
+ detail.setMasterId(summary.getId());
|
|
|
|
|
+ detail.setTaskId(mainTask.getId());
|
|
|
|
|
+ detail.setDocumentName(document.getDocumentName());
|
|
|
|
|
+ detail.setDocumentNumber(document.getDocumentNumber() != null ? document.getDocumentNumber() : "");
|
|
|
|
|
+ detail.setAuditedUnitName("");
|
|
|
|
|
+ detail.setFileSource("监审单位反馈文件");
|
|
|
|
|
+ detail.setPageCount(0);
|
|
|
|
|
+ detail.setAttachmentUrl(document.getFeedbackDocumentUrl() != null ? document.getFeedbackDocumentUrl() : "");
|
|
|
|
|
+ detail.setOrderNum(orderNum++);
|
|
|
|
|
+ detail.setIsDeleted("0");
|
|
|
|
|
+ costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 档案校对通过后,异步生成Word卷宗
|
|
* 档案校对通过后,异步生成Word卷宗
|
|
|
|
|
+ * 顺序:封面(-1) -> 目录(-2) -> 14个资料(1-13) -> 封底(-3)
|
|
|
*
|
|
*
|
|
|
* @param taskId 任务ID
|
|
* @param taskId 任务ID
|
|
|
*/
|
|
*/
|
|
|
@Async
|
|
@Async
|
|
|
public void generateWordArchiveAsync(String taskId) {
|
|
public void generateWordArchiveAsync(String taskId) {
|
|
|
|
|
+ CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
try {
|
|
try {
|
|
|
- // 1. 查询任务的所有资料归纳主表(按序号排序)
|
|
|
|
|
- // 2. 遍历每个主表,获取其明细列表(按序号排序)
|
|
|
|
|
- // 3. 按顺序读取每个明细对应的文件
|
|
|
|
|
- // 4. 将所有文件合并为一个完整的Word文档
|
|
|
|
|
- // 5. 保存生成的Word卷宗文件
|
|
|
|
|
|
|
+ logger.info("开始生成Word卷宗,任务ID:{}", taskId);
|
|
|
|
|
|
|
|
- System.out.println("开始生成Word卷宗,任务ID:" + taskId);
|
|
|
|
|
|
|
+ // 查询任务的所有资料归纳主表(包含封面、目录、封底)
|
|
|
|
|
+ List<CostProjectTaskMaterialSummary> allSummaryList =
|
|
|
|
|
+ costProjectTaskMaterialSummaryManager.listAllByTaskId(taskId);
|
|
|
|
|
|
|
|
- // 示例代码框架(需要根据实际情况实现)
|
|
|
|
|
- List<CostProjectTaskMaterialSummary> summaryList =
|
|
|
|
|
- costProjectTaskMaterialSummaryManager.listByTaskId(taskId);
|
|
|
|
|
|
|
+ // 创建Word文档
|
|
|
|
|
+ XWPFDocument document = new XWPFDocument();
|
|
|
|
|
+ boolean isFirstDocument = true;
|
|
|
|
|
+
|
|
|
|
|
+ // 按顺序合并:封面(-1) -> 目录(-2) -> 14个资料(1-13) -> 封底(-3)
|
|
|
|
|
+ // 排序:-1, -2, 1, 2, ..., 13, -3
|
|
|
|
|
+ allSummaryList.sort((a, b) -> {
|
|
|
|
|
+ int orderA = a.getMaterialOrderNum() != null ? a.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 sortB = orderB == -1 ? -100 : (orderB == -2 ? -99 : (orderB == -3 ? 100 : orderB));
|
|
|
|
|
+ return Integer.compare(sortA, sortB);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 遍历所有主表,从明细表获取附件URL进行合并
|
|
|
|
|
+ for (CostProjectTaskMaterialSummary summary : allSummaryList) {
|
|
|
|
|
+ logger.info("合并资料:{}", summary.getMaterialName());
|
|
|
|
|
+ List<CostProjectTaskMaterialSummaryDetail> detailList = summary.getDetailList();
|
|
|
|
|
+ if (detailList != null && !detailList.isEmpty()) {
|
|
|
|
|
+ detailList.sort(Comparator.comparing(d -> d.getOrderNum() != null ? d.getOrderNum() : 0));
|
|
|
|
|
+ for (CostProjectTaskMaterialSummaryDetail detail : detailList) {
|
|
|
|
|
+ if (StringUtil.isNotEmpty(detail.getAttachmentUrl())) {
|
|
|
|
|
+ isFirstDocument = mergeDocumentFile(document, detail.getAttachmentUrl(), isFirstDocument);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 按序号排序
|
|
|
|
|
- summaryList.sort(Comparator.comparing(CostProjectTaskMaterialSummary::getMaterialOrderNum));
|
|
|
|
|
|
|
+ // 生成输出文件路径
|
|
|
|
|
+ String fileName = FileUploadUtil.generateFileName("卷宗_" + taskId + ".docx");
|
|
|
|
|
+ String outputPath = FileUploadUtil.generateSavePath(
|
|
|
|
|
+ EipConfig.getUploadPath(), fileName, "docx");
|
|
|
|
|
|
|
|
- // 创建Word文档
|
|
|
|
|
- XWPFDocument document = new XWPFDocument();
|
|
|
|
|
-
|
|
|
|
|
- for (CostProjectTaskMaterialSummary summary : summaryList) {
|
|
|
|
|
- // 获取明细列表
|
|
|
|
|
- List<CostProjectTaskMaterialSummaryDetail> detailList = summary.getDetailList();
|
|
|
|
|
- if (detailList != null) {
|
|
|
|
|
- detailList.sort(Comparator.comparing(CostProjectTaskMaterialSummaryDetail::getOrderNum));
|
|
|
|
|
-
|
|
|
|
|
- for (CostProjectTaskMaterialSummaryDetail detail : detailList) {
|
|
|
|
|
- // 读取文件内容并添加到Word文档
|
|
|
|
|
- if (StringUtil.isNotEmpty(detail.getAttachmentUrl())) {
|
|
|
|
|
- try {
|
|
|
|
|
-
|
|
|
|
|
- // 读取Word文件
|
|
|
|
|
- java.io.FileInputStream fis = new java.io.FileInputStream(detail.getAttachmentUrl());
|
|
|
|
|
- XWPFDocument sourceDoc = new XWPFDocument(fis);
|
|
|
|
|
-
|
|
|
|
|
- // 合并段落
|
|
|
|
|
- for (XWPFParagraph srcPara : sourceDoc.getParagraphs()) {
|
|
|
|
|
- XWPFParagraph destPara = document.createParagraph();
|
|
|
|
|
- // 复制段落样式
|
|
|
|
|
- destPara.setAlignment(srcPara.getAlignment());
|
|
|
|
|
- destPara.setIndentationLeft(srcPara.getIndentationLeft());
|
|
|
|
|
- destPara.setIndentationRight(srcPara.getIndentationRight());
|
|
|
|
|
- destPara.setSpacingBefore(srcPara.getSpacingBefore());
|
|
|
|
|
- destPara.setSpacingAfter(srcPara.getSpacingAfter());
|
|
|
|
|
- for (XWPFRun srcRun : srcPara.getRuns()) {
|
|
|
|
|
- XWPFRun destRun = destPara.createRun();
|
|
|
|
|
- destRun.setText(srcRun.getText(0));
|
|
|
|
|
- destRun.setBold(srcRun.isBold());
|
|
|
|
|
- destRun.setItalic(srcRun.isItalic());
|
|
|
|
|
- destRun.setUnderline(srcRun.getUnderline());
|
|
|
|
|
- destRun.setStrikeThrough(srcRun.isStrikeThrough());
|
|
|
|
|
- destRun.setFontSize(srcRun.getFontSize());
|
|
|
|
|
- if (srcRun.getFontFamily() != null) {
|
|
|
|
|
- destRun.setFontFamily(srcRun.getFontFamily());
|
|
|
|
|
- }
|
|
|
|
|
- if (srcRun.getColor() != null) {
|
|
|
|
|
- destRun.setColor(srcRun.getColor());
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 添加分页符(每个文档之间分页)
|
|
|
|
|
- XWPFParagraph pageBreakPara = document.createParagraph();
|
|
|
|
|
- XWPFRun pageBreakRun = pageBreakPara.createRun();
|
|
|
|
|
- pageBreakRun.addBreak(org.apache.poi.xwpf.usermodel.BreakType.PAGE);
|
|
|
|
|
-
|
|
|
|
|
- sourceDoc.close();
|
|
|
|
|
- fis.close();
|
|
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- System.err.println("合并文件失败:" + detail.getDocumentName() + ",错误:" + e.getMessage());
|
|
|
|
|
- e.printStackTrace();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- //保存Word文档
|
|
|
|
|
- String outputPath = "卷宗_" + taskId + ".docx";
|
|
|
|
|
- FileOutputStream out = new FileOutputStream(outputPath);
|
|
|
|
|
- document.write(out);
|
|
|
|
|
- out.close();
|
|
|
|
|
- document.close();
|
|
|
|
|
-
|
|
|
|
|
- System.out.println("Word卷宗生成完成,任务ID:" + taskId);
|
|
|
|
|
-
|
|
|
|
|
- // 更新任务的归档状态
|
|
|
|
|
- CostProjectTask task = costProjectTaskManager.getById(taskId);
|
|
|
|
|
|
|
+ // 确保目录存在
|
|
|
|
|
+ java.io.File outputFile = new java.io.File(outputPath);
|
|
|
|
|
+ if (!outputFile.getParentFile().exists()) {
|
|
|
|
|
+ outputFile.getParentFile().mkdirs();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 保存Word文档
|
|
|
|
|
+ FileOutputStream out = new FileOutputStream(outputPath);
|
|
|
|
|
+ document.write(out);
|
|
|
|
|
+ out.close();
|
|
|
|
|
+ document.close();
|
|
|
|
|
+
|
|
|
|
|
+ // 生成访问URL
|
|
|
|
|
+ String archiveUrl = FileUploadUtil.getPathFileName(outputPath, fileName);
|
|
|
|
|
+
|
|
|
|
|
+ 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) {
|
|
|
if (task != null) {
|
|
if (task != null) {
|
|
|
- task.setIsGd("1");
|
|
|
|
|
|
|
+ task.setArchiveStatus("3");
|
|
|
costProjectTaskManager.updateById(task);
|
|
costProjectTaskManager.updateById(task);
|
|
|
- System.out.println("任务归档状态已更新,任务ID:" + taskId);
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ logger.error("生成Word卷宗失败,任务ID:,错误:{}", taskId, e.getMessage(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 合并单个文档文件到主文档(保持原始样式)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param document 主文档
|
|
|
|
|
+ * @param fileUrl 文件URL(如:/profile/upload/20251116/xxx.docx)
|
|
|
|
|
+ * @param isFirstDocument 是否是第一个文档
|
|
|
|
|
+ * @return 是否是第一个文档(用于下次调用)
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean mergeDocumentFile(XWPFDocument document, String fileUrl, boolean isFirstDocument) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ String filePath = fileUrl;
|
|
|
|
|
+ // 处理路径:/profile 开头的路径需要替换为实际路径
|
|
|
|
|
+ if (filePath.startsWith("/profile")) {
|
|
|
|
|
+ filePath = EipConfig.getProfile() + filePath.substring(8);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ java.io.File file = new java.io.File(filePath);
|
|
|
|
|
+ if (!file.exists()) {
|
|
|
|
|
+ logger.warn("文件不存在:{}(原始路径:{})", filePath, fileUrl);
|
|
|
|
|
+ return isFirstDocument;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 添加分页符(非第一个文档)
|
|
|
|
|
+ if (!isFirstDocument) {
|
|
|
|
|
+ XWPFParagraph pageBreakPara = document.createParagraph();
|
|
|
|
|
+ XWPFRun pageBreakRun = pageBreakPara.createRun();
|
|
|
|
|
+ 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());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ sourceDoc.close();
|
|
|
|
|
+ fis.close();
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
|
|
- System.err.println("生成Word卷宗失败,任务ID:" + taskId + ",错误:" + e.getMessage());
|
|
|
|
|
|
|
+ logger.error("合并文件失败:{},错误:{}", fileUrl, e.getMessage(), e);
|
|
|
|
|
+ return isFirstDocument;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -741,7 +897,7 @@ public class AsyncMaterialSummaryService {
|
|
|
try {
|
|
try {
|
|
|
CostProjectTaskMaterialSummary summary = costProjectTaskMaterialSummaryManager.getById(masterId);
|
|
CostProjectTaskMaterialSummary summary = costProjectTaskMaterialSummaryManager.getById(masterId);
|
|
|
if (summary == null) {
|
|
if (summary == null) {
|
|
|
- System.err.println("资料归纳主表不存在,ID:" + masterId);
|
|
|
|
|
|
|
+ logger.warn("资料归纳主表不存在,ID:{}", masterId);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -765,22 +921,21 @@ public class AsyncMaterialSummaryService {
|
|
|
summary.setTotalPageCount(String.valueOf(totalPageCount));
|
|
summary.setTotalPageCount(String.valueOf(totalPageCount));
|
|
|
costProjectTaskMaterialSummaryManager.updateById(summary);
|
|
costProjectTaskMaterialSummaryManager.updateById(summary);
|
|
|
|
|
|
|
|
- System.out.println("资料归纳【" + summary.getMaterialName() + "】总页数已更新:" + totalPageCount);
|
|
|
|
|
|
|
+ logger.info("资料归纳【{}】总页数已更新:{}", summary.getMaterialName(), totalPageCount);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
|
|
- System.err.println("更新主表总页数失败,主表ID:" + masterId + ",错误:" + e.getMessage());
|
|
|
|
|
|
|
+ logger.error("更新主表总页数失败,主表ID:{},错误:{}", masterId, e.getMessage(), e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 异步统计每个资料归纳主表的总页数(所有明细的页数之和)
|
|
|
|
|
|
|
+ * 统计每个资料归纳主表的总页数(所有明细的页数之和)
|
|
|
*
|
|
*
|
|
|
* @param taskId 任务ID
|
|
* @param taskId 任务ID
|
|
|
*/
|
|
*/
|
|
|
public void calculatePageCountAsync(String taskId) {
|
|
public void calculatePageCountAsync(String taskId) {
|
|
|
try {
|
|
try {
|
|
|
- System.out.println("开始异步统计页数,任务ID:" + taskId);
|
|
|
|
|
|
|
+ logger.info("开始异步统计页数,任务ID:{}", taskId);
|
|
|
|
|
|
|
|
// 查询任务的所有资料归纳主表
|
|
// 查询任务的所有资料归纳主表
|
|
|
List<CostProjectTaskMaterialSummary> summaryList = costProjectTaskMaterialSummaryManager.listByTaskId(taskId);
|
|
List<CostProjectTaskMaterialSummary> summaryList = costProjectTaskMaterialSummaryManager.listByTaskId(taskId);
|
|
@@ -806,14 +961,13 @@ public class AsyncMaterialSummaryService {
|
|
|
summary.setTotalPageCount(String.valueOf(totalPageCount));
|
|
summary.setTotalPageCount(String.valueOf(totalPageCount));
|
|
|
costProjectTaskMaterialSummaryManager.updateById(summary);
|
|
costProjectTaskMaterialSummaryManager.updateById(summary);
|
|
|
|
|
|
|
|
- System.out.println("资料归纳【" + summary.getMaterialName() + "】统计完成,总页数:" + totalPageCount);
|
|
|
|
|
|
|
+ logger.info("资料归纳【{}】统计完成,总页数:{}", summary.getMaterialName(), totalPageCount);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- System.out.println("页数统计完成,任务ID:" + taskId);
|
|
|
|
|
|
|
+ logger.info("页数统计完成,任务ID:{}", taskId);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- e.printStackTrace();
|
|
|
|
|
- System.err.println("统计页数失败,任务ID:" + taskId + ",错误:" + e.getMessage());
|
|
|
|
|
|
|
+ logger.error("统计页数失败,任务ID:{},错误:{}", taskId, e.getMessage(), e);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -844,7 +998,7 @@ public class AsyncMaterialSummaryService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- System.err.println("计算文件页数失败,文件:" + fileUrl + ",错误:" + e.getMessage());
|
|
|
|
|
|
|
+ logger.error("计算文件页数失败,文件:{},错误:{}", fileUrl, e.getMessage(), e);
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -862,7 +1016,7 @@ public class AsyncMaterialSummaryService {
|
|
|
try {
|
|
try {
|
|
|
String filePath = fileUrl;
|
|
String filePath = fileUrl;
|
|
|
if (filePath.startsWith("/profile")) {
|
|
if (filePath.startsWith("/profile")) {
|
|
|
- filePath = com.hotent.config.EipConfig.getProfile() + filePath.substring(8);
|
|
|
|
|
|
|
+ filePath = EipConfig.getProfile() + filePath.substring(8);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fis = new java.io.FileInputStream(filePath);
|
|
fis = new java.io.FileInputStream(filePath);
|
|
@@ -874,7 +1028,7 @@ public class AsyncMaterialSummaryService {
|
|
|
return pageCount > 0 ? pageCount : 1;
|
|
return pageCount > 0 ? pageCount : 1;
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- System.err.println("读取Word页数失败,文件:" + fileUrl + ",错误:" + e.getMessage());
|
|
|
|
|
|
|
+ logger.error("读取Word页数失败,文件:{},错误:{}", fileUrl, e.getMessage(), e);
|
|
|
// 读取失败默认返回1页
|
|
// 读取失败默认返回1页
|
|
|
return 1;
|
|
return 1;
|
|
|
} finally {
|
|
} finally {
|
|
@@ -887,9 +1041,435 @@ public class AsyncMaterialSummaryService {
|
|
|
fis.close();
|
|
fis.close();
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- System.err.println("关闭文件流失败:" + e.getMessage());
|
|
|
|
|
|
|
+ logger.warn("关闭文件流失败:{}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 卷宗校对文书生成功能 ====================
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 生成卷宗文书(封面/目录/封底)
|
|
|
|
|
+ * id为空是新增,id不为空是编辑
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param req 生成请求
|
|
|
|
|
+ * @return 生成的文书URL
|
|
|
|
|
+ */
|
|
|
|
|
+ public String generateArchiveDocument(com.hotent.project.req.ArchiveProofreadReq req) throws Exception {
|
|
|
|
|
+ Integer documentType = req.getDocumentType();
|
|
|
|
|
+ String existingId = req.getId();
|
|
|
|
|
+
|
|
|
|
|
+ // 如果id不为空,从数据库获取已有记录的documentType(id是主表ID)
|
|
|
|
|
+ if (StringUtil.isNotEmpty(existingId)) {
|
|
|
|
|
+ CostProjectTaskMaterialSummary existing = costProjectTaskMaterialSummaryManager.getById(existingId);
|
|
|
|
|
+ if (existing == null) {
|
|
|
|
|
+ throw new RuntimeException("主表记录不存在:" + existingId);
|
|
|
|
|
+ }
|
|
|
|
|
+ Integer orderNum = existing.getMaterialOrderNum();
|
|
|
|
|
+ if (orderNum != null && orderNum == -1) {
|
|
|
|
|
+ documentType = 1;
|
|
|
|
|
+ } else if (orderNum != null && orderNum == -2) {
|
|
|
|
|
+ documentType = 2;
|
|
|
|
|
+ } else if (orderNum != null && orderNum == -3) {
|
|
|
|
|
+ documentType = 3;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ throw new RuntimeException("无效的文书记录");
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ String templatePath;
|
|
|
|
|
+ String documentName;
|
|
|
|
|
+
|
|
|
|
|
+ switch (documentType) {
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ templatePath = coverTemplatePath;
|
|
|
|
|
+ documentName = "案卷封面";
|
|
|
|
|
+ if (StringUtil.isEmpty(templatePath)) {
|
|
|
|
|
+ throw new RuntimeException("案卷封面模板路径未配置");
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ templatePath = catalogTemplatePath;
|
|
|
|
|
+ documentName = "卷内目录";
|
|
|
|
|
+ if (StringUtil.isEmpty(templatePath)) {
|
|
|
|
|
+ throw new RuntimeException("卷内目录模板路径未配置");
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ templatePath = backCoverTemplatePath;
|
|
|
|
|
+ documentName = "案卷封底";
|
|
|
|
|
+ if (StringUtil.isEmpty(templatePath)) {
|
|
|
|
|
+ throw new RuntimeException("案卷封底模板路径未配置");
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ throw new RuntimeException("不支持的文书类型:" + documentType);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查模板文件是否存在
|
|
|
|
|
+ java.io.File templateFile = new java.io.File(templatePath);
|
|
|
|
|
+ if (!templateFile.exists()) {
|
|
|
|
|
+ throw new RuntimeException("模板文件不存在:" + templatePath);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 生成文书
|
|
|
|
|
+ String outputUrl = generateDocumentFromTemplate(templatePath, documentName, req);
|
|
|
|
|
+
|
|
|
|
|
+ // 保存到数据库(主表+明细表)
|
|
|
|
|
+ int orderNum = -documentType; // -1封面、-2目录、-3封底
|
|
|
|
|
+ String masterId;
|
|
|
|
|
+
|
|
|
|
|
+ if (StringUtil.isNotEmpty(existingId)) {
|
|
|
|
|
+ // 编辑:existingId是主表ID,查找对应的明细记录
|
|
|
|
|
+ masterId = existingId;
|
|
|
|
|
+ CostProjectTaskMaterialSummaryDetail existingDetail = costProjectTaskMaterialSummaryDetailManager.getOne(
|
|
|
|
|
+ new LambdaQueryWrapper<CostProjectTaskMaterialSummaryDetail>()
|
|
|
|
|
+ .eq(CostProjectTaskMaterialSummaryDetail::getMasterId, masterId)
|
|
|
|
|
+ .eq(CostProjectTaskMaterialSummaryDetail::getIsDeleted, "0")
|
|
|
|
|
+ );
|
|
|
|
|
+ if (existingDetail != null) {
|
|
|
|
|
+ // 更新已有明细
|
|
|
|
|
+ existingDetail.setAttachmentUrl(outputUrl);
|
|
|
|
|
+ existingDetail.setGenerateTime(java.time.LocalDateTime.now());
|
|
|
|
|
+ costProjectTaskMaterialSummaryDetailManager.updateById(existingDetail);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 创建新明细
|
|
|
|
|
+ CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail();
|
|
|
|
|
+ detail.setMasterId(masterId);
|
|
|
|
|
+ detail.setTaskId(req.getTaskId());
|
|
|
|
|
+ detail.setDocumentName(documentName);
|
|
|
|
|
+ detail.setFileSource("系统生成电子文书");
|
|
|
|
|
+ detail.setAttachmentUrl(outputUrl);
|
|
|
|
|
+ detail.setOrderNum(1);
|
|
|
|
|
+ detail.setGenerateTime(java.time.LocalDateTime.now());
|
|
|
|
|
+ detail.setIsDeleted("0");
|
|
|
|
|
+ costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 新增:创建主表记录
|
|
|
|
|
+ CostProjectTaskMaterialSummary summary = new CostProjectTaskMaterialSummary();
|
|
|
|
|
+ summary.setTaskId(req.getTaskId());
|
|
|
|
|
+ summary.setMaterialOrderNum(orderNum);
|
|
|
|
|
+ summary.setMaterialName(documentName);
|
|
|
|
|
+ summary.setIsDeleted("0");
|
|
|
|
|
+ costProjectTaskMaterialSummaryManager.save(summary);
|
|
|
|
|
+ masterId = summary.getId();
|
|
|
|
|
+
|
|
|
|
|
+ // 创建明细记录
|
|
|
|
|
+ CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail();
|
|
|
|
|
+ detail.setMasterId(masterId);
|
|
|
|
|
+ detail.setTaskId(req.getTaskId());
|
|
|
|
|
+ detail.setDocumentName(documentName);
|
|
|
|
|
+ detail.setFileSource("系统生成电子文书");
|
|
|
|
|
+ detail.setAttachmentUrl(outputUrl);
|
|
|
|
|
+ detail.setOrderNum(1);
|
|
|
|
|
+ detail.setGenerateTime(java.time.LocalDateTime.now());
|
|
|
|
|
+ detail.setIsDeleted("0");
|
|
|
|
|
+ costProjectTaskMaterialSummaryDetailManager.save(detail);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return outputUrl;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 根据模板生成文书
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param templatePath 模板路径
|
|
|
|
|
+ * @param documentName 文书名称
|
|
|
|
|
+ * @param req 请求参数
|
|
|
|
|
+ * @return 生成的文书URL
|
|
|
|
|
+ */
|
|
|
|
|
+ private String generateDocumentFromTemplate(String templatePath, String documentName,
|
|
|
|
|
+ com.hotent.project.req.ArchiveProofreadReq req) throws Exception {
|
|
|
|
|
+ java.io.FileInputStream fis = null;
|
|
|
|
|
+ XWPFDocument document = null;
|
|
|
|
|
+ java.io.FileOutputStream fos = null;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ // 读取模板
|
|
|
|
|
+ fis = new java.io.FileInputStream(templatePath);
|
|
|
|
|
+ document = new XWPFDocument(fis);
|
|
|
|
|
+
|
|
|
|
|
+ // 构建替换映射
|
|
|
|
|
+ Map<String, String> replacements = buildReplacementMap(req);
|
|
|
|
|
+
|
|
|
|
|
+ // 根据文书类型进行不同处理
|
|
|
|
|
+ switch (req.getDocumentType()) {
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ // 案卷封面
|
|
|
|
|
+ generateCoverDocument(document, replacements);
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ // 卷内目录
|
|
|
|
|
+ generateCatalogDocument(document, replacements, req.getTaskId());
|
|
|
|
|
+ break;
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ // 案卷封底
|
|
|
|
|
+ generateBackCoverDocument(document, replacements);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 生成输出文件路径
|
|
|
|
|
+ String fileName = FileUploadUtil.generateFileName(documentName + ".docx");
|
|
|
|
|
+ String outputPath = FileUploadUtil.generateSavePath(
|
|
|
|
|
+ EipConfig.getUploadPath(), fileName, "docx");
|
|
|
|
|
+
|
|
|
|
|
+ // 确保目录存在
|
|
|
|
|
+ java.io.File outputFile = new java.io.File(outputPath);
|
|
|
|
|
+ if (!outputFile.getParentFile().exists()) {
|
|
|
|
|
+ outputFile.getParentFile().mkdirs();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 写入文件
|
|
|
|
|
+ fos = new java.io.FileOutputStream(outputPath);
|
|
|
|
|
+ document.write(fos);
|
|
|
|
|
+
|
|
|
|
|
+ // 返回访问URL
|
|
|
|
|
+ return FileUploadUtil.getPathFileName(outputPath, fileName);
|
|
|
|
|
+
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ // 关闭资源
|
|
|
|
|
+ try {
|
|
|
|
|
+ if (fos != null) fos.close();
|
|
|
|
|
+ if (document != null) document.close();
|
|
|
|
|
+ if (fis != null) fis.close();
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ logger.warn("关闭文件流失败:{}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 构建替换映射
|
|
|
|
|
+ * 自动从数据库获取:年份、监审项目名称、被监审单位、监审期间(开始-结束年度)、监审人员、办结时间
|
|
|
|
|
+ * 需要用户传递:价格主管部门、卷宗号、保管期间周期、立卷人、立卷日期、检查人、检查日期、备注
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<String, String> buildReplacementMap(com.hotent.project.req.ArchiveProofreadReq req) {
|
|
|
|
|
+ Map<String, String> map = new java.util.HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取任务信息
|
|
|
|
|
+ CostProjectTask task = costProjectTaskManager.getById(req.getTaskId());
|
|
|
|
|
+
|
|
|
|
|
+ // 从数据库获取立项审批信息(包含监审组人员)
|
|
|
|
|
+ CostProjectApproval approval = costProjectApprovalManager.getOne(
|
|
|
|
|
+ new LambdaQueryWrapper<CostProjectApproval>()
|
|
|
|
|
+ .eq(CostProjectApproval::getProjectId, task.getProjectId())
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 自动获取的字段 ==========
|
|
|
|
|
+ Org org = orgManager.getById(approval.getOrgId());
|
|
|
|
|
+ map.put("{价格主管部门或成本监审机构}", org.getName());
|
|
|
|
|
+ map.put("{年份}", task.getYear());
|
|
|
|
|
+ map.put("{监审项目名称}", task.getProjectName());
|
|
|
|
|
+ map.put("{被监审单位}", task.getAuditedUnitName());
|
|
|
|
|
+
|
|
|
|
|
+ // 监审期间(解析开始-结束年度,格式如:2024,2025,2023 逗号分隔)
|
|
|
|
|
+ String startYear = "";
|
|
|
|
|
+ String endYear = "";
|
|
|
|
|
+ String auditPeriod = task.getAuditPeriod();
|
|
|
|
|
+ if (StringUtil.isNotEmpty(auditPeriod)) {
|
|
|
|
|
+ String[] years = auditPeriod.split(",");
|
|
|
|
|
+ int minYear = Integer.MAX_VALUE;
|
|
|
|
|
+ int maxYear = Integer.MIN_VALUE;
|
|
|
|
|
+ for (String year : years) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ int y = Integer.parseInt(year.trim());
|
|
|
|
|
+ if (y < minYear) minYear = y;
|
|
|
|
|
+ if (y > maxYear) maxYear = y;
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (minYear != Integer.MAX_VALUE) {
|
|
|
|
|
+ startYear = String.valueOf(minYear);
|
|
|
|
|
+ endYear = String.valueOf(maxYear);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put("{监审开始年度}", startYear);
|
|
|
|
|
+ map.put("{监审结束年度}", endYear);
|
|
|
|
|
+
|
|
|
|
|
+ // 监审组负责人及人员(将ID转换为姓名)
|
|
|
|
|
+ String auditGroupNames = "";
|
|
|
|
|
+ if (approval != null && StringUtil.isNotEmpty(approval.getAuditGroup())) {
|
|
|
|
|
+ String[] userIds = approval.getAuditGroup().split(",");
|
|
|
|
|
+ StringBuilder names = new StringBuilder();
|
|
|
|
|
+ for (String userId : userIds) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ User user = userManager.get(userId.trim());
|
|
|
|
|
+ if (user != null) {
|
|
|
|
|
+ if (names.length() > 0) {
|
|
|
|
|
+ names.append(",");
|
|
|
|
|
+ }
|
|
|
|
|
+ names.append(user.getFullname());
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ auditGroupNames = names.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put("{监审组负责人及人员}", auditGroupNames);
|
|
|
|
|
+
|
|
|
|
|
+ // 监审办结时间(任务状态为办结时,取更新时间,格式:xxxx年xx月)
|
|
|
|
|
+ String auditEndTime = "";
|
|
|
|
|
+ if ("400".equals(task.getStatus()) && task.getUpdateTime() != null) {
|
|
|
|
|
+ auditEndTime = task.getUpdateTime().getYear() + "年" + task.getUpdateTime().getMonthValue() + "月";
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put("{监审办结时间}", auditEndTime);
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 需要用户传递的字段 ==========
|
|
|
|
|
+ map.put("{卷宗号}", req.getArchiveNo() != null ? req.getArchiveNo() : "");
|
|
|
|
|
+ map.put("{保管期间周期}", req.getRetentionPeriod() != null ? req.getRetentionPeriod() : "");
|
|
|
|
|
+
|
|
|
|
|
+ // ========== 卷宗统计信息 ==========
|
|
|
|
|
+ // 获取14个资料归纳的总页数
|
|
|
|
|
+ List<CostProjectTaskMaterialSummary> summaryList = costProjectTaskMaterialSummaryManager.listByTaskId(req.getTaskId());
|
|
|
|
|
+ summaryList = summaryList.stream()
|
|
|
|
|
+ .filter(s -> s.getMaterialOrderNum() != null && s.getMaterialOrderNum() > 0)
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ int totalPageCount = 0;
|
|
|
|
|
+ for (CostProjectTaskMaterialSummary summary : summaryList) {
|
|
|
|
|
+ if (summary.getTotalPageCount() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ totalPageCount += Integer.parseInt(summary.getTotalPageCount());
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ map.put("{卷宗件数}", "1"); // 默认1件
|
|
|
|
|
+ map.put("{卷宗页数}", String.valueOf(totalPageCount));
|
|
|
|
|
+ map.put("{第几件}", "1"); // 默认第1件
|
|
|
|
|
+
|
|
|
|
|
+ return map;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 生成案卷封面
|
|
|
|
|
+ */
|
|
|
|
|
+ private void generateCoverDocument(XWPFDocument document, Map<String, String> replacements) {
|
|
|
|
|
+ SmartTemplateWriter.writeToTemplate(document, replacements);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 生成卷内目录(只填充表格,不替换占位符)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void generateCatalogDocument(XWPFDocument document, Map<String, String> replacements, String taskId) {
|
|
|
|
|
+ // 获取资料归纳列表,生成目录表格
|
|
|
|
|
+ List<CostProjectTaskMaterialSummary> summaryList = costProjectTaskMaterialSummaryManager.listByTaskId(taskId);
|
|
|
|
|
+
|
|
|
|
|
+ // 过滤掉封面、目录、封底(负数序号)
|
|
|
|
|
+ summaryList = summaryList.stream()
|
|
|
|
|
+ .filter(s -> s.getMaterialOrderNum() != null && s.getMaterialOrderNum() > 0)
|
|
|
|
|
+ .sorted(Comparator.comparing(CostProjectTaskMaterialSummary::getMaterialOrderNum))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ // 构建目录数据
|
|
|
|
|
+ List<CompleteTemplateProcessor.TableRowData> tableDataList = new java.util.ArrayList<>();
|
|
|
|
|
+ int currentPage = 1;
|
|
|
|
|
+
|
|
|
|
|
+ for (CostProjectTaskMaterialSummary summary : summaryList) {
|
|
|
|
|
+ CompleteTemplateProcessor.TableRowData rowData =
|
|
|
|
|
+ new CompleteTemplateProcessor.TableRowData();
|
|
|
|
|
+ rowData.setDocumentName(summary.getMaterialName());
|
|
|
|
|
+
|
|
|
|
|
+ int pageCount = 0;
|
|
|
|
|
+ if (summary.getTotalPageCount() != null) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ pageCount = Integer.parseInt(summary.getTotalPageCount());
|
|
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
|
|
+ pageCount = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ rowData.setPageCount(pageCount);
|
|
|
|
|
+
|
|
|
|
|
+ // 计算页码范围作为备注
|
|
|
|
|
+ if (pageCount > 0) {
|
|
|
|
|
+ rowData.setRemark(currentPage + "-" + (currentPage + pageCount - 1));
|
|
|
|
|
+ currentPage += pageCount;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ rowData.setRemark("—");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tableDataList.add(rowData);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 只填充表格数据,
|
|
|
|
|
+ if (!tableDataList.isEmpty()) {
|
|
|
|
|
+ processTableData(document, tableDataList);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 生成案卷封底
|
|
|
|
|
+ */
|
|
|
|
|
+ private void generateBackCoverDocument(XWPFDocument document, Map<String, String> replacements) {
|
|
|
|
|
+ SmartTemplateWriter.writeToTemplate(document, replacements);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理目录表格数据
|
|
|
|
|
+ */
|
|
|
|
|
+ private void processTableData(XWPFDocument document, List<CompleteTemplateProcessor.TableRowData> dataList) {
|
|
|
|
|
+ List<XWPFTable> tables = document.getTables();
|
|
|
|
|
+ if (tables.isEmpty()) {
|
|
|
|
|
+ logger.warn("未找到表格");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ XWPFTable table = tables.get(0);
|
|
|
|
|
+
|
|
|
|
|
+ // 找到模板行(第二行,第一行是表头)
|
|
|
|
|
+ int templateRowIndex = 1;
|
|
|
|
|
+ if (table.getRows().size() <= templateRowIndex) {
|
|
|
|
|
+ logger.warn("表格行数不足");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取模板行的单元格数量
|
|
|
|
|
+ int cellCount = table.getRow(templateRowIndex).getTableCells().size();
|
|
|
|
|
+
|
|
|
|
|
+ // 删除模板行
|
|
|
|
|
+ table.removeRow(templateRowIndex);
|
|
|
|
|
+
|
|
|
|
|
+ // 从模板行位置开始插入数据行
|
|
|
|
|
+ for (int i = 0; i < dataList.size(); i++) {
|
|
|
|
|
+ CompleteTemplateProcessor.TableRowData data = dataList.get(i);
|
|
|
|
|
+ XWPFTableRow newRow = table.insertNewTableRow(templateRowIndex + i);
|
|
|
|
|
+ // 创建单元格
|
|
|
|
|
+ for (int j = 0; j < cellCount; j++) {
|
|
|
|
|
+ newRow.addNewTableCell();
|
|
|
|
|
+ }
|
|
|
|
|
+ fillTableRow(newRow, i + 1, data);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 填充表格行数据
|
|
|
|
|
+ */
|
|
|
|
|
+ private void fillTableRow(XWPFTableRow row, int sequence,
|
|
|
|
|
+ CompleteTemplateProcessor.TableRowData data) {
|
|
|
|
|
+ List<XWPFTableCell> cells = row.getTableCells();
|
|
|
|
|
+ if (cells.size() >= 4) {
|
|
|
|
|
+ setCellText(cells.get(0), String.valueOf(sequence));
|
|
|
|
|
+ setCellText(cells.get(1), data.getDocumentName());
|
|
|
|
|
+ setCellText(cells.get(2), data.getPageCount() > 0 ? String.valueOf(data.getPageCount()) : "");
|
|
|
|
|
+ setCellText(cells.get(3), data.getRemark() != null ? data.getRemark() : "");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 设置单元格文本
|
|
|
|
|
+ */
|
|
|
|
|
+ private void setCellText(XWPFTableCell cell, String text) {
|
|
|
|
|
+ // 清除现有内容
|
|
|
|
|
+ for (int i = cell.getParagraphs().size() - 1; i >= 0; i--) {
|
|
|
|
|
+ cell.removeParagraph(i);
|
|
|
|
|
+ }
|
|
|
|
|
+ // 添加新内容
|
|
|
|
|
+ XWPFParagraph paragraph = cell.addParagraph();
|
|
|
|
|
+ XWPFRun run = paragraph.createRun();
|
|
|
|
|
+ run.setText(text);
|
|
|
|
|
+ paragraph.setAlignment(ParagraphAlignment.CENTER);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|