From c71b875c4db6be9154c5f1c98e69cb651fff6774 Mon Sep 17 00:00:00 2001 From: luotaiqian <1147642922@qq.com> Date: Tue, 25 Aug 2026 17:46:31 +0800 Subject: [PATCH] archive file --- .../EvalProcessControlExecutor.java | 175 ++++++++++++------ .../request/EvalProjectArchiveFileAddCmd.java | 36 ++-- .../EvalProjectArchiveFileUpdateCmd.java | 5 + .../response/EvalProjectArchiveFileCo.java | 3 + 4 files changed, 135 insertions(+), 84 deletions(-) diff --git a/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalProcessControlExecutor.java b/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalProcessControlExecutor.java index caf9b927..b518be82 100644 --- a/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalProcessControlExecutor.java +++ b/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/institution/EvalProcessControlExecutor.java @@ -7,7 +7,6 @@ import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.extern.slf4j.Slf4j; import org.qinan.safetyeval.app.executor.institution.support.EvalCmdCopy; import org.qinan.safetyeval.app.executor.institution.support.EvalProjectNodeSupport; @@ -37,9 +36,10 @@ import org.qinan.safetyeval.infrastructure.convertor.EvalProcessControlConvertor import org.qinan.safetyeval.infrastructure.convertor.EvalProjectMemberDoConvertor; import org.qinan.safetyeval.infrastructure.dataobject.*; import org.qinan.safetyeval.infrastructure.mapper.*; +import org.qinan.safetyeval.infrastructure.persistence.domainobject.EvalProjectArchiveFileDO; +import org.qinan.safetyeval.infrastructure.persistence.mapper.EvalProjectArchiveFileMapper; import org.qinan.safetyeval.infrastructure.persistence.queryservice.*; import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults; -import org.qinan.safetyeval.infrastructure.utils.CommonUtil; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; @@ -99,12 +99,12 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi { @Resource private EvalProcessControlMapper evalProcessControlMapper; @Resource - private EvalProjectDocMapper evalProjectDocMapper; + private EvalRiskParticipantMapper evalRiskParticipantMapper; + @Resource + private EvalProjectArchiveFileMapper evalProjectArchiveFileMapper; @Resource private EvalSignTaskMapper evalSignTaskMapper; @Resource - private EvalCustomerMapper evalCustomerMapper; - @Resource private WpsDocQueryService wpsDocQueryService; @Resource private SafetyMessageGateway safetyMessageGateway; @@ -370,7 +370,8 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi { projectStageSyncService.onArchived(projectId, cmd.getArchiveTransferorName(), cmd.getArchiveArchivistName()); // 写入项目预警记录(存在则更新,不存在则新增) upsertProjectWaring(project); - + // 归档项目资料:将所有项目文件以流程自动记录来源存入 eval_project_archive_file + saveAutoArchiveFiles(projectId, project); projectStageSyncService.onNodeCompleted(projectId, ProjectStageEnum.ARCHIVE.getNode()); return SingleResponse.success(evalProcessControlConvertor.toProcessCO(entity)); } @@ -381,6 +382,8 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi { Long orgId = project.getOrgId(); List files = new java.util.ArrayList<>(); + // 风险分析/项目组-参与人签字(eval_risk_participant:risk_id 非空为风险分析,为空为项目组) + files.addAll(listRiskParticipantFiles(projectId)); // 业务合同-合同扫描件 files.addAll(evalContractQueryService.listProjectFiles(projectId, orgId)); // 现场踏勘-附件 @@ -528,63 +531,115 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi { } /** - * 归档时将 listProjectFiles 查询出的所有项目文件以 ARCHIVED 资料类型合并写入 eval_project_doc.project_doc_url。 - * 写入前先移除原有 materialType=ARCHIVED 的记录,再追加本次归档的文件后更新。 + * 归档项目资料:将 listProjectFiles 查询出的所有项目文件写入 eval_project_archive_file(来源:流程自动记录)。 + * 写入前先删除该项目 record_source=auto_process_record 的旧记录,再逐文件构建新增数据。 */ - private void upsertArchivedProjectDocs(Long projectId, EvalProjectEntity project) { - List files = listProjectFiles(projectId).getData(); - // 将每个文件 projectDocUrl 中的 JSON 数组扁平化:数组内每个文件对象拆分为独立的资料条目 - List archivedItems = new ArrayList<>(); - if (!CollectionUtils.isEmpty(files)) { - for (EvalProjectFileCO f : files) { - List urlObjects = parseFileUrlObjects(f.getProjectDocUrl()); - String itemName = f.getItemName(); - for (JSONObject obj : urlObjects) { - EvalProjectDocMaterialItemCO item = new EvalProjectDocMaterialItemCO(); - String name = obj.getStr("name"); - String fName = StringUtils.hasText(name) ? CommonUtil.EMPTY : name; - item.setMaterialName(itemName + fName); - item.setProjectDocUrl(obj.getStr("url")); - item.setMaterialType(MaterialCategory.ARCHIVED.getMsg()); - archivedItems.add(item); - } - } - } + private void saveAutoArchiveFiles(Long projectId, EvalProjectEntity project) { + // 先删除该项目流程自动记录来源的旧档案文件,避免重复归档产生脏数据 + evalProjectArchiveFileMapper.delete(new LambdaQueryWrapper() + .eq(EvalProjectArchiveFileDO::getProjectId, String.valueOf(projectId)) + .eq(EvalProjectArchiveFileDO::getRecordSource, ProjectArchiveFileSourceEnum.AUTO_PROCESS_RECORD.getCode())); - EvalProjectDocDO docDO = evalProjectDocMapper.selectOne(new LambdaQueryWrapper() - .select(EvalProjectDocDO::getId, EvalProjectDocDO::getProjectDocUrl) - .eq(EvalProjectDocDO::getProjectId, projectId)); - if (docDO == null) { - EvalCustomerDO evalCustomerDO = evalCustomerMapper.selectOne(new LambdaQueryWrapper() - .select(EvalCustomerDO::getCustomerName) - .eq(EvalCustomerDO::getId, project.getCustomerId())); - docDO = new EvalProjectDocDO(); - docDO.setOrgId(project.getOrgId()); - docDO.setProjectId(projectId); - docDO.setProjectNo(project.getProjectNo()); - docDO.setCustomerName(evalCustomerDO.getCustomerName()); - docDO.setProjectName(project.getProjectName()); - docDO.setEvalTypeCode(project.getEvalTypeCode()); - docDO.setProjectDocUrl(JSON.toJSONString(archivedItems)); - docDO.setRemarks(MaterialCategory.ARCHIVED.getMsg()); - InsertFieldDefaults.apply(docDO); - evalProjectDocMapper.insert(docDO); - } else { - List existing = new ArrayList<>(); - if (StringUtils.hasText(docDO.getProjectDocUrl())) { - List parsed = JSONUtil.toList(docDO.getProjectDocUrl(), EvalProjectDocMaterialItemCO.class); - if (parsed != null) { - existing.addAll(parsed); - } - } - // 先移除原有 ARCHIVED 类型的资料,再追加本次归档的文件 - String archivedVal = MaterialCategory.ARCHIVED.getVal(); - existing.removeIf(item -> archivedVal.equals(item.getMaterialType())); - existing.addAll(archivedItems); - evalProjectDocMapper.update(new LambdaUpdateWrapper() - .eq(EvalProjectDocDO::getId, docDO.getId()) - .set(EvalProjectDocDO::getProjectDocUrl, JSON.toJSONString(existing))); + List files = listProjectFiles(projectId).getData(); + if (CollectionUtils.isEmpty(files)) { + return; } + for (EvalProjectFileCO file : files) { + ProjectStageEnum stage = resolveStageByMsg(file.getProcessName()); + for (JSONObject obj : parseFileUrlObjects(file.getProjectDocUrl())) { + if (!StringUtils.hasText(obj.getStr("url"))) { + continue; + } + evalProjectArchiveFileMapper.insert(buildArchiveFileDO(projectId, project, file, stage, obj)); + } + } + } + + /** + * 构建单条档案文件记录:archiveType 按业务节点映射 ArchiveTypeEnum,businessNode 存 ProjectStageEnum 英文标识。 + */ + private EvalProjectArchiveFileDO buildArchiveFileDO(Long projectId, EvalProjectEntity project, + EvalProjectFileCO file, ProjectStageEnum stage, JSONObject obj) { + String urlName = obj.getStr("name"); + EvalProjectArchiveFileDO archiveFileDO = new EvalProjectArchiveFileDO(); + archiveFileDO.setOrgId(project.getOrgId()); + archiveFileDO.setProjectId(String.valueOf(projectId)); + archiveFileDO.setFileUrl(obj.getStr("url")); + archiveFileDO.setFileName(StringUtils.hasText(urlName) ? urlName : file.getItemName()); + archiveFileDO.setArchiveType(resolveArchiveType(stage).getCode()); + archiveFileDO.setBusinessNode(stage != null ? stage.getVal() : file.getProcessName()); + archiveFileDO.setRecordSource(ProjectArchiveFileSourceEnum.AUTO_PROCESS_RECORD.getCode()); + InsertFieldDefaults.apply(archiveFileDO); + return archiveFileDO; + } + + /** + * 根据流程中文名(ProjectStageEnum.msg,如 业务合同/现场踏勘)查找对应阶段枚举,未匹配返回 null。 + */ + private ProjectStageEnum resolveStageByMsg(String processName) { + if (!StringUtils.hasText(processName)) { + return null; + } + for (ProjectStageEnum stage : ProjectStageEnum.values()) { + if (stage.getMsg().equals(processName)) { + return stage; + } + } + return null; + } + + /** + * 按业务节点映射档案类型:风险分析→项目风险分析,业务合同→技术服务合同,项目组→项目组织文件, + * 现场踏勘→现场勘察资料,报告编制→评价报告,内部审核/技术审核→审核记录,过程控制→过程控制文件, + * 其余→其他。 + */ + private ArchiveTypeEnum resolveArchiveType(ProjectStageEnum stage) { + if (stage == null) { + return ArchiveTypeEnum.OTHER; + } + switch (stage) { + case RISK_ANALYSIS: + return ArchiveTypeEnum.RISK_ANALYSIS; + case BUSINESS_CONTRACT: + return ArchiveTypeEnum.TECH_SERVICE_CONTRACT; + case PROJECT_GROUP: + return ArchiveTypeEnum.PROJECT_ORG_FILE; + case SITE_SURVEY: + return ArchiveTypeEnum.SITE_SURVEY; + case REPORT_PREPARATION: + return ArchiveTypeEnum.EVALUATION_REPORT; + case INTERNAL_REVIEW: + case TECHNICAL_REVIEW: + return ArchiveTypeEnum.REVIEW_RECORD; + case PROCESS_CONTROL: + return ArchiveTypeEnum.PROCESS_CONTROL; + default: + return ArchiveTypeEnum.OTHER; + } + } + + /** + * 查询 eval_risk_participant 参与人签字文件:risk_id 非空为风险分析参与人,为空为项目组成员。 + */ + private List listRiskParticipantFiles(Long projectId) { + List files = new ArrayList<>(); + List participants = evalRiskParticipantMapper.selectList( + new LambdaQueryWrapper() + .eq(EvalRiskParticipantDO::getProjectId, projectId) + .isNotNull(EvalRiskParticipantDO::getSignFileUrl)); + if (CollectionUtils.isEmpty(participants)) { + return files; + } + for (EvalRiskParticipantDO participant : participants) { + ProjectStageEnum stage = participant.getRiskId() != null + ? ProjectStageEnum.RISK_ANALYSIS : ProjectStageEnum.PROJECT_GROUP; + EvalProjectFileCO co = new EvalProjectFileCO(); + co.setProcessName(stage.getMsg()); + co.setItemName(stage.getMsg() + "签字"); + co.setProjectDocUrl(participant.getSignFileUrl()); + files.add(co); + } + return files; } /** diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileAddCmd.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileAddCmd.java index 984b32aa..f573ade3 100644 --- a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileAddCmd.java +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileAddCmd.java @@ -5,6 +5,7 @@ import lombok.Data; import org.qinan.safetyeval.domain.constant.ArchiveTypeEnum; import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; import java.io.Serializable; /** @@ -17,47 +18,34 @@ import java.io.Serializable; public class EvalProjectArchiveFileAddCmd implements Serializable { private static final long serialVersionUID = 1L; - /** - * 项目ID - */ @ApiModelProperty(value = "项目ID", required = true) @NotBlank(message = "项目ID不能为空") private String projectId; - /** - * 文件地址 - */ + @ApiModelProperty(value = "文件地址", required = true) @NotBlank(message = "文件地址不能为空") private String fileUrl; - /** - * 文件名称 - */ + @ApiModelProperty(value = "文件名称", required = true) - @NotBlank(message = "文件名称不能为空") + @Size(max = 100, message = "文件名称长度不能超过100") private String fileName; - /** - * ArchiveTypeEnum.REMARKS - */ + @ApiModelProperty(value = ArchiveTypeEnum.REMARKS, required = true) @NotBlank(message = ArchiveTypeEnum.REMARKS + "不能为空") + @Size(max = 100, message = "档案类型长度不能超过100") private String archiveType; - /** - * 业务节点 - */ @ApiModelProperty(value = "业务节点", required = true) @NotBlank(message = "业务节点不能为空") + @Size(max = 32, message = "业务节点长度不能超过32") private String businessNode; - /** - * 来源 auto_process_record流程自动记录,upload_additional_files 补充上传 - */ + @ApiModelProperty(value = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传", required = true) @NotBlank(message = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传不能为空") + @Size(max = 32, message = "来源长度不能超过32") private String recordSource; - /** - * 环境 - */ - @ApiModelProperty(value = "环境") - private String env; + @ApiModelProperty(value = "备注") + @Size(max = 200, message = "备注长度不能超过200") + private String remarks; } diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileUpdateCmd.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileUpdateCmd.java index 3b4cdde8..4b0c324e 100644 --- a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileUpdateCmd.java +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/request/EvalProjectArchiveFileUpdateCmd.java @@ -7,6 +7,7 @@ import org.qinan.safetyeval.domain.constant.ArchiveTypeEnum; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; import java.io.Serializable; /** @@ -56,4 +57,8 @@ public class EvalProjectArchiveFileUpdateCmd implements Serializable { @ApiModelProperty(value = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传", required = true) @NotBlank(message = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传不能为空") private String recordSource; + + @ApiModelProperty(value = "备注") + @Size(max = 200, message = "备注长度不能超过200") + private String remarks; } diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/response/EvalProjectArchiveFileCo.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/response/EvalProjectArchiveFileCo.java index 4d833526..dfe687d3 100644 --- a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/response/EvalProjectArchiveFileCo.java +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/file/response/EvalProjectArchiveFileCo.java @@ -54,4 +54,7 @@ public class EvalProjectArchiveFileCo extends ClientObject { @ApiModelProperty(value = "创建人") protected String createName; + + @ApiModelProperty(value = "备注") + private String remarks; }