package com.hotent.project.service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.hotent.base.util.StringUtil; import com.hotent.config.EipConfig; import com.hotent.project.manager.*; import com.hotent.project.model.*; import com.hotent.surveyinfo.manager.CostSurveyTemplateUploadManager; import com.hotent.surveyinfo.model.CostSurveyTemplateUpload; 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.uc.util.ContextUtil; 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.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.FileOutputStream; import java.time.LocalDateTime; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 异步资料归纳服务 * * @company 山西清众科技股份有限公司 * @author 超级管理员 * @since 2025-12-02 */ @Service public class AsyncMaterialSummaryService { private static final Logger logger = LoggerFactory.getLogger(AsyncMaterialSummaryService.class); @Autowired private CostProjectTaskMaterialSummaryManager costProjectTaskMaterialSummaryManager; @Autowired private CostProjectTaskMaterialSummaryDetailManager costProjectTaskMaterialSummaryDetailManager; @Autowired private CostProjectDocumentManager costProjectDocumentManager; @Autowired private CostProjectTaskManager costProjectTaskManager; @Autowired private CostSurveyTemplateUploadManager costSurveyTemplateUploadManager; @Autowired private CostProjectTaskMaterialManager costProjectTaskMaterialManager; @Autowired private CostProjectDeliberateManager costProjectDeliberateManager; @Autowired private CostProjectTaskAdjustmentRecordManager adjustmentRecordManager; @Autowired private CostProjectTaskEvidenceManager costProjectTaskEvidenceManager; @Autowired 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; /** * 生成资料归纳主表(14个基础资料类别)- 核心逻辑 * * @param mainTask 主任务 * @param childTasks 子任务列表 */ public void generateMaterialSummary(CostProjectTask mainTask, List childTasks) { try { // 定义14个基础资料类别 String[] materialNames = { "成本监审报告(含成本监审报告签发稿、送达回证)", "被监审单位申请定(调)价报告(复印件)", "成本监审通知书(含送达回证)", "经营者需提供成本资料清单", "《政府定价成本监审调查表》", "成本监审补充资料通知书(含送达回证)", "成本审核初步意见告知书(含送达回证)", "经营者书面反馈的材料", "成本审核初步意见表(集体审议用)", "成本监审集体审议记录", "成本监审工作底稿", "成本监审提取资料登记表", "提取的成本资料和会计凭证等复印件", "中止定价成本监审料通知书(含送达回证)" }; // 为主任务生成14个资料归纳主表记录 for (int i = 0; i < materialNames.length; i++) { CostProjectTaskMaterialSummary summary = new CostProjectTaskMaterialSummary(); summary.setTaskId(mainTask.getId()); summary.setMaterialName(materialNames[i]); summary.setMaterialOrderNum(i + 1); summary.setIsDeleted("0"); costProjectTaskMaterialSummaryManager.createOrUpdate(summary); // 根据不同的资料类别生成对应的明细记录 generateDetailsByMaterialType(summary, mainTask, childTasks, i + 1); } } catch (Exception e) { // 记录异常日志,但不影响主流程 logger.error("生成资料归纳失败", e); } } /** * 根据资料类别生成对应的明细记录 * * @param summary 资料归纳主表 * @param mainTask 主任务 * @param childTasks 子任务列表 * @param materialType 资料类别序号(1-13) */ private void generateDetailsByMaterialType(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, int materialType) { try { // 查询项目下的所有文书 List documents = costProjectDocumentManager.getListByProjectId(mainTask.getProjectId()); if (documents == null) { documents = new java.util.ArrayList<>(); } switch (materialType) { case 1: // 成本监审报告(含成本监审报告签发稿、送达回证) generateType1Details(summary, mainTask, documents); break; case 2: // 被监审单位申请定(调)价报告(复印件) generateType2Details(summary, mainTask, childTasks, documents); break; case 3: // 成本监审通知书(含送达回证) generateType3Details(summary, mainTask, childTasks, documents); break; case 4: // 经营者需提供成本资料清单 generateType4Details(summary, mainTask, childTasks, documents); break; case 5: // 《政府定价成本监审调查表》 generateType5Details(summary, mainTask, childTasks, documents); break; case 6: // 成本监审补充资料通知书(含送达回证) generateType6Details(summary, mainTask, childTasks, documents); break; case 7: // 成本审核初步意见告知书(含送达回证) generateType7Details(summary, mainTask, childTasks, documents); break; case 8: // 经营者书面反馈的材料 generateType8Details(summary, mainTask, childTasks, documents); break; case 9: // 成本审核初步意见表(集体审议用) generateType9Details(summary, mainTask, childTasks, documents); break; case 10: // 成本监审集体审议记录 generateType10Details(summary, mainTask, documents); break; case 11: // 成本监审工作底稿 generateType11Details(summary, mainTask, childTasks, documents); break; case 12: // 成本监审提取资料登记表 generateType12Details(summary, mainTask, childTasks, documents); break; case 13: // 提取的成本资料和会计凭证等复印件 generateType13Details(summary, mainTask, childTasks, documents); break; case 14: // 中止定价成本监审料通知书(含送达回证) generateType14Details(summary, mainTask, childTasks, documents); break; default: throw new RuntimeException("未知的资料类型"); } } catch (Exception e) { logger.error("生成资料类型 {} 的明细时出错:{}", materialType, e.getMessage(), e); // 继续执行,不中断整个流程 } } //1 卷宗封面 //2 卷内目录 //3 政府定价成本监审结论报告 //4 成本监审通知书 //5 成本审核初步意见告知书 //6 成本审核初步意见表 //7 成本监审集体审议记录 //8 成本监审工作底稿 //9 成本监审提取资料登记表 //10 成本监审补充资料通知书 //11 中止定价成本监审通知书 //12 送达回证 //13 成本监审卷宗备考表 // ==================== 类型1:成本监审报告(含成本监审报告签发稿、送达回证) ==================== // A.成本监审报告(含成本监审报告签发稿) // 包括成本监审报告、报告签发稿等文书。 private void generateType1Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List documents) { int orderNum = 1; // 获取"成本监审报告"、"成本监审报告签发稿"、"送达回证" List matchedDocuments = documents.stream() .filter(doc -> "3".equals(doc.getDocumentType()) || "3-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName()) ) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } // ==================== 类型2:被监审单位申请定(调)价报告(复印件) ==================== // 被监审单位申请定(调)价报告等。 //来源:从“监审立项”附件获取。 private void generateType2Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"申请定(调)价报告" List matchedDocuments = documents.stream() .filter(doc -> "申请定(调)价报告".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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("监审主体上传文件"); detail.setPageCount(0); detail.setAttachmentUrl(document.getScanDocumentUrl() != null ? document.getScanDocumentUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); 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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(approval.getAccordingFileUrl()); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } // ==================== 类型3:成本监审通知书(含送达回证) ==================== // 包括成本监审通知书、送达回证等文书。 //来源:从“监审文书”中获取。 private void generateType3Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // "成本监审通知书"和"送达回证" List matchedDocuments = documents.stream() .filter(doc -> "4".equals(doc.getDocumentType()) || "4-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } // ==================== 类型4:经营者需提供成本资料清单(提取资料) ==================== // 成本监审任务中的资料报送要求。 //来源:从“监审任务部署”中获取。 private void generateType4Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"成本资料清单" List matchedDocuments = documents.stream() .filter(doc -> "9".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } for (CostProjectTask childTask : childTasks) { List list = costProjectTaskEvidenceManager.list( new LambdaQueryWrapper().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.setAuditedUnitId(childTask.getAuditedUnitId()); 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:《政府定价成本监审调查表》 ==================== // 各被监审单位的“成本监审调查表”文档。 //来源:从“监审任务”中获取各被监审单位填报的成本监审调查表。 private void generateType5Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; for (CostProjectTask childTask : childTasks) { List costSurveyTemplateUploads = costSurveyTemplateUploadManager.listByTaskId(childTask.getId()); for (CostSurveyTemplateUpload upload : costSurveyTemplateUploads) { if ("1".equals(upload.getIsUpload()) && StringUtil.isNotEmpty(upload.getFileUrl())) { CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail(); detail.setMasterId(summary.getId()); detail.setTaskId(mainTask.getId()); detail.setDocumentName(upload.getSurveyTemplateName() != null ? upload.getSurveyTemplateName() : "政府定价成本监审调查表"); detail.setDocumentNumber(""); detail.setAuditedUnitId(childTask.getAuditedUnitId()); detail.setAuditedUnitName(childTask.getAuditedUnitName() != null ? childTask.getAuditedUnitName() : ""); detail.setFileSource("监审单位反馈文件"); detail.setPageCount(0); detail.setAttachmentUrl(upload.getFileUrl()); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } } // 成本调查表(kkkk) } // ==================== 类型6:成本监审补充资料通知书(含送达回证) ==================== // 监审主体发送给各被监审单位的补充资料通知书、送达回证等文书。 //来源:从“监审文书”中获取。 private void generateType6Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; List matchedDocuments = documents.stream() .filter(doc -> "10".equals(doc.getDocumentType()) || "10-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } // ==================== 类型7:成本审核初步意见告知书(含送达回证) ==================== // 监审主体发送给各被监审单位的初步意见告知书、送达回证等文书。 // 来源:从“监审文书”中获取。 private void generateType7Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"成本审核初步意见告知书"和"送达回证" List matchedDocuments = documents.stream() .filter(doc -> "5".equals(doc.getDocumentType()) || "5-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } // ==================== 类型8:经营者书面反馈的材料 ==================== // 各被监审单位对初步意见告知书的意见反馈资料。 //来源:从“监审任务”中获取反馈意见。 private void generateType8Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"书面反馈材料"(来源:监审单位反馈文件) List matchedDocuments = documents.stream() .filter(doc -> "书面反馈材料".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("监审单位反馈文件"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } // 获取被监审单位的反馈意见和反馈资料 for (CostProjectTask childTask : childTasks) { List list = preliminaryOpinionManager.list( new LambdaQueryWrapper<>(CostProjectTaskPreliminaryOpinion.class) .eq(CostProjectTaskPreliminaryOpinion::getTaskId, childTask.getId()) ); for (CostProjectTaskPreliminaryOpinion opinion : list) { // 只处理有反馈资料的记录 if (StringUtil.isNotEmpty(opinion.getFeedbackMaterials())) { CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail(); detail.setMasterId(summary.getId()); detail.setTaskId(mainTask.getId()); detail.setDocumentName("书面反馈材料"); detail.setDocumentNumber(""); detail.setAuditedUnitId(childTask.getAuditedUnitId()); detail.setAuditedUnitName(childTask.getAuditedUnitName() != null ? childTask.getAuditedUnitName() : ""); detail.setFileSource("监审单位反馈文件"); detail.setPageCount(0); detail.setAttachmentUrl(opinion.getFeedbackMaterials()); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } } } // ==================== 类型9:成本审核初步意见表(集体审议用) ==================== // 来源:从“监审文书”中获取 private void generateType9Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"成本审核初步意见表" List matchedDocuments = documents.stream() .filter(doc -> "6".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } // ==================== 类型10:成本监审集体审议记录 ==================== // 来源:从“监审文书”中获取。 private void generateType10Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List documents) { int orderNum = 1; // 获取"成本监审集体审议记录" List matchedDocuments = documents.stream() .filter(doc -> "7".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } // 获取集体审议记录 List list = costProjectDeliberateManager.list( new LambdaQueryWrapper().eq(CostProjectDeliberate::getTaskId, mainTask.getId()) ); for (CostProjectDeliberate deliberate : list) { // 只处理有附件的审议记录 if (StringUtil.isNotEmpty(deliberate.getAttachmentUrl())) { CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail(); detail.setMasterId(summary.getId()); detail.setTaskId(mainTask.getId()); detail.setDocumentName("成本监审集体审议记录"); detail.setDocumentNumber(""); detail.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(deliberate.getAttachmentUrl()); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } } // ==================== 类型11:成本监审工作底稿 ==================== // 来源:从“监审文书”中获取。 private void generateType11Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"成本监审工作底稿" List matchedDocuments = documents.stream() .filter(doc -> "8".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } // 获取核增核减记录(工作底稿的一部分) for (CostProjectTask childTask : childTasks) { List costProjectTaskAdjustmentRecords = adjustmentRecordManager.listByTaskId(childTask.getId()); for (CostProjectTaskAdjustmentRecord record : costProjectTaskAdjustmentRecords) { // 只处理有附件的记录 if (StringUtil.isNotEmpty(record.getAttachmentUrl())) { CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail(); detail.setMasterId(summary.getId()); detail.setTaskId(mainTask.getId()); detail.setDocumentName(record.getSubject() != null ? record.getSubject() + "-工作底稿" : "成本监审工作底稿"); detail.setDocumentNumber(""); detail.setAuditedUnitId(childTask.getAuditedUnitId()); detail.setAuditedUnitName(childTask.getAuditedUnitName() != null ? childTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(record.getAttachmentUrl()); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } } } // ==================== 类型12:成本监审提取资料登记表 ==================== // 来源:从“监审文书”中获取。 private void generateType12Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"成本监审提取资料登记表" List matchedDocuments = documents.stream() .filter(doc -> "9".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("系统生成电子文书"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } // 获取子任务的资料登记表 for (CostProjectTask childTask : childTasks) { List list = costProjectTaskEvidenceManager.list( new LambdaQueryWrapper().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.setAuditedUnitId(childTask.getAuditedUnitId()); 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); } } } } // ==================== 类型13:提取的成本资料和会计凭证等复印件 ==================== // 来源:各被监审单位首次及补充材料时提交的资料,包括综合性材料、财会资料等。 private void generateType13Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"成本资料和会计凭证"(来源:被监审单位提交的资料) List matchedDocuments = documents.stream() .filter(doc -> "成本资料和会计凭证".equals(doc.getDocumentType())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("监审单位反馈文件"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } // 获取子任务的资料登记表 for (CostProjectTask childTask : childTasks) { // 获取任务的报送资料要求(被监审单位提交的补充资料) List list = costProjectTaskMaterialManager.list( new LambdaQueryWrapper<>(CostProjectTaskMaterial.class) .eq(CostProjectTaskMaterial::getTaskId, childTask.getId()) ); for (CostProjectTaskMaterial material : list) { // 只处理已上传的资料 if ("1".equals(material.getIsUpload()) && StringUtil.isNotEmpty(material.getFileUrl())) { CostProjectTaskMaterialSummaryDetail detail = new CostProjectTaskMaterialSummaryDetail(); detail.setMasterId(summary.getId()); detail.setTaskId(mainTask.getId()); detail.setDocumentName(material.getInformationName() != null ? material.getInformationName() : "补充资料"); detail.setDocumentNumber(""); detail.setAuditedUnitId(childTask.getAuditedUnitId()); detail.setAuditedUnitName(childTask.getAuditedUnitName() != null ? childTask.getAuditedUnitName() : ""); detail.setFileSource("监审单位反馈文件"); detail.setPageCount(0); detail.setAttachmentUrl(material.getFileUrl()); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } } } // ==================== 类型14:中止定价成本监审料通知书(含送达回证) ==================== // 来源:从“监审文书”中获取。 private void generateType14Details(CostProjectTaskMaterialSummary summary, CostProjectTask mainTask, List childTasks, List documents) { int orderNum = 1; // 获取"中止定价成本监审通知书"(来源:被监审单位提交的资料) List matchedDocuments = documents.stream() .filter(doc -> "11".equals(doc.getDocumentType()) || "11-12".equals(doc.getDocumentType()+"-"+doc.getDocumentTypeName())) .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.setAuditedUnitId(mainTask.getAuditedUnitId()); detail.setAuditedUnitName(mainTask.getAuditedUnitName() != null ? mainTask.getAuditedUnitName() : ""); detail.setFileSource("监审单位反馈文件"); detail.setPageCount(0); detail.setAttachmentUrl(document.getActUrl() != null ? document.getActUrl() : ""); detail.setOrderNum(orderNum++); detail.setIsDeleted("0"); costProjectTaskMaterialSummaryDetailManager.save(detail); } } /** * 档案校对通过后,异步生成Word卷宗 * 顺序:封面(-1) -> 目录(-2) -> 14个资料(1-13) -> 封底(-3) * * @param taskId 任务ID */ @Async public void generateWordArchiveAsync(String taskId) { CostProjectTask task = costProjectTaskManager.getById(taskId); try { logger.info("开始生成Word卷宗,任务ID:{}", taskId); // 查询任务的所有资料归纳主表(包含封面、目录、封底) List allSummaryList = costProjectTaskMaterialSummaryManager.listAllByTaskId(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 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); } } } } // 生成输出文件路径 String fileName = FileUploadUtil.generateFileName("卷宗_" + taskId + ".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(); } // 保存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) { task.setArchiveStatus("3"); costProjectTaskManager.updateById(task); } 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) { logger.error("合并文件失败:{},错误:{}", fileUrl, e.getMessage(), e); return isFirstDocument; } } /** * 更新单个资料归纳主表的总页数 * * @param masterId 主表ID */ public void updateMasterTotalPageCount(String masterId) { try { CostProjectTaskMaterialSummary summary = costProjectTaskMaterialSummaryManager.getById(masterId); if (summary == null) { logger.warn("资料归纳主表不存在,ID:{}", masterId); return; } int totalPageCount = 0; // 查询该主表的所有明细 List detailList = costProjectTaskMaterialSummaryDetailManager.list( new LambdaQueryWrapper() .eq(CostProjectTaskMaterialSummaryDetail::getMasterId, masterId) .eq(CostProjectTaskMaterialSummaryDetail::getIsDeleted, "0") ); // 累加所有明细的页数 for (CostProjectTaskMaterialSummaryDetail detail : detailList) { if (detail.getPageCount() != null) { totalPageCount += detail.getPageCount(); } } // 更新主表的总页数 summary.setTotalPageCount(String.valueOf(totalPageCount)); costProjectTaskMaterialSummaryManager.updateById(summary); logger.info("资料归纳【{}】总页数已更新:{}", summary.getMaterialName(), totalPageCount); } catch (Exception e) { logger.error("更新主表总页数失败,主表ID:{},错误:{}", masterId, e.getMessage(), e); } } /** * 统计每个资料归纳主表的总页数(所有明细的页数之和) * * @param taskId 任务ID */ public void calculatePageCountAsync(String taskId) { try { logger.info("开始异步统计页数,任务ID:{}", taskId); // 查询任务的所有资料归纳主表 List summaryList = costProjectTaskMaterialSummaryManager.listByTaskId(taskId); for (CostProjectTaskMaterialSummary summary : summaryList) { int totalPageCount = 0; // 获取该主表的所有明细 if (summary.getDetailList() != null && !summary.getDetailList().isEmpty()) { for (CostProjectTaskMaterialSummaryDetail detail : summary.getDetailList()) { if (StringUtil.isNotEmpty(detail.getAttachmentUrl())) { // 统计该明细的页数 int pageCount = calculateFilePageCount(detail.getAttachmentUrl()); detail.setPageCount(pageCount); costProjectTaskMaterialSummaryDetailManager.updateById(detail); // 累加到总页数 totalPageCount += pageCount; } } } // 更新主表的总页数 summary.setTotalPageCount(String.valueOf(totalPageCount)); costProjectTaskMaterialSummaryManager.updateById(summary); logger.info("资料归纳【{}】统计完成,总页数:{}", summary.getMaterialName(), totalPageCount); } logger.info("页数统计完成,任务ID:{}", taskId); } catch (Exception e) { logger.error("统计页数失败,任务ID:{},错误:{}", taskId, e.getMessage(), e); } } /** * 计算文件页数(公共方法,可被外部调用) * * @param fileUrl 文件URL或路径 * @return 页数 */ public int calculateFilePageCount(String fileUrl) { try { if (StringUtil.isEmpty(fileUrl)) { 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文件需要读取实际页数 return getWordPageCount(fileUrl); } else { // 其他格式默认1页 return 1; } } catch (Exception e) { logger.error("计算文件页数失败,文件:{},错误:{}", fileUrl, e.getMessage(), e); return 0; } } /** * 获取Word文档的页数 * * @param fileUrl 文件URL或路径(如:/profile/upload/20251116/xxx.docx) * @return 页数 */ private int getWordPageCount(String fileUrl) { java.io.FileInputStream fis = null; XWPFDocument document = null; try { String filePath = fileUrl; if (filePath.startsWith("/profile")) { filePath = EipConfig.getProfile() + filePath.substring(8); } fis = new java.io.FileInputStream(filePath); document = new XWPFDocument(fis); // 获取页数 int pageCount = document.getProperties().getExtendedProperties().getUnderlyingProperties().getPages(); return pageCount > 0 ? pageCount : 1; } catch (Exception e) { logger.error("读取Word页数失败,文件:{},错误:{}", fileUrl, e.getMessage(), e); // 读取失败默认返回1页 return 1; } finally { // 关闭资源 try { if (document != null) { document.close(); } if (fis != null) { fis.close(); } } catch (Exception e) { 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.getRelatedId(); // 如果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; CostProjectTaskMaterialSummary existingSummary = costProjectTaskMaterialSummaryManager.getById(masterId); if (existingSummary != null) { // 更新task的卷宗号和归档人 CostProjectTask task = costProjectTaskManager.getById(existingSummary.getTaskId()); if (task != null) { task.setArchiveNo(req.getArchiveNo()); task.setArchiveUser(ContextUtil.getCurrentUser().getFullname()); costProjectTaskManager.updateById(task); } } CostProjectTaskMaterialSummaryDetail existingDetail = costProjectTaskMaterialSummaryDetailManager.getOne( new LambdaQueryWrapper() .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(); // 更新task的卷宗号和归档人 CostProjectTask task = costProjectTaskManager.getById(req.getTaskId()); if (task != null) { task.setArchiveNo(req.getArchiveNo()); task.setArchiveUser(ContextUtil.getCurrentUser().getAccount()); costProjectTaskManager.updateById(task); } // 创建明细记录 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 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 buildReplacementMap(com.hotent.project.req.ArchiveProofreadReq req) { Map map = new java.util.HashMap<>(); // 从数据库获取任务信息 CostProjectTask task = costProjectTaskManager.getById(req.getTaskId()); // 从数据库获取立项审批信息(包含监审组人员) CostProjectApproval approval = costProjectApprovalManager.getOne( new LambdaQueryWrapper() .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 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件 map.put("{备注}", req.getRemark()); return map; } /** * 生成案卷封面 */ private void generateCoverDocument(XWPFDocument document, Map replacements) { SmartTemplateWriter.writeToTemplate(document, replacements); } /** * 生成卷内目录(只填充表格,不替换占位符) */ private void generateCatalogDocument(XWPFDocument document, Map replacements, String taskId) { // 获取资料归纳列表,生成目录表格 List summaryList = costProjectTaskMaterialSummaryManager.listByTaskId(taskId); // 过滤掉封面、目录、封底(负数序号) summaryList = summaryList.stream() .filter(s -> s.getMaterialOrderNum() != null && s.getMaterialOrderNum() > 0) .sorted(Comparator.comparing(CostProjectTaskMaterialSummary::getMaterialOrderNum)) .collect(Collectors.toList()); // 构建目录数据 List 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 replacements) { SmartTemplateWriter.writeToTemplate(document, replacements); } /** * 处理目录表格数据 */ private void processTableData(XWPFDocument document, List dataList) { List tables = document.getTables(); if (tables.isEmpty()) { logger.warn("未找到表格"); return; } XWPFTable table = tables.get(0); // 找到模板行(第二行,第一行是表头) int templateRowIndex = 0; 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 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); } }