archive file
parent
a8db7ee59c
commit
c71b875c4d
|
|
@ -7,7 +7,6 @@ import cn.hutool.json.JSONObject;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.qinan.safetyeval.app.executor.institution.support.EvalCmdCopy;
|
import org.qinan.safetyeval.app.executor.institution.support.EvalCmdCopy;
|
||||||
import org.qinan.safetyeval.app.executor.institution.support.EvalProjectNodeSupport;
|
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.convertor.EvalProjectMemberDoConvertor;
|
||||||
import org.qinan.safetyeval.infrastructure.dataobject.*;
|
import org.qinan.safetyeval.infrastructure.dataobject.*;
|
||||||
import org.qinan.safetyeval.infrastructure.mapper.*;
|
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.persistence.queryservice.*;
|
||||||
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
|
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
|
||||||
import org.qinan.safetyeval.infrastructure.utils.CommonUtil;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
@ -99,12 +99,12 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi {
|
||||||
@Resource
|
@Resource
|
||||||
private EvalProcessControlMapper evalProcessControlMapper;
|
private EvalProcessControlMapper evalProcessControlMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private EvalProjectDocMapper evalProjectDocMapper;
|
private EvalRiskParticipantMapper evalRiskParticipantMapper;
|
||||||
|
@Resource
|
||||||
|
private EvalProjectArchiveFileMapper evalProjectArchiveFileMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private EvalSignTaskMapper evalSignTaskMapper;
|
private EvalSignTaskMapper evalSignTaskMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private EvalCustomerMapper evalCustomerMapper;
|
|
||||||
@Resource
|
|
||||||
private WpsDocQueryService wpsDocQueryService;
|
private WpsDocQueryService wpsDocQueryService;
|
||||||
@Resource
|
@Resource
|
||||||
private SafetyMessageGateway safetyMessageGateway;
|
private SafetyMessageGateway safetyMessageGateway;
|
||||||
|
|
@ -370,7 +370,8 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi {
|
||||||
projectStageSyncService.onArchived(projectId, cmd.getArchiveTransferorName(), cmd.getArchiveArchivistName());
|
projectStageSyncService.onArchived(projectId, cmd.getArchiveTransferorName(), cmd.getArchiveArchivistName());
|
||||||
// 写入项目预警记录(存在则更新,不存在则新增)
|
// 写入项目预警记录(存在则更新,不存在则新增)
|
||||||
upsertProjectWaring(project);
|
upsertProjectWaring(project);
|
||||||
|
// 归档项目资料:将所有项目文件以流程自动记录来源存入 eval_project_archive_file
|
||||||
|
saveAutoArchiveFiles(projectId, project);
|
||||||
projectStageSyncService.onNodeCompleted(projectId, ProjectStageEnum.ARCHIVE.getNode());
|
projectStageSyncService.onNodeCompleted(projectId, ProjectStageEnum.ARCHIVE.getNode());
|
||||||
return SingleResponse.success(evalProcessControlConvertor.toProcessCO(entity));
|
return SingleResponse.success(evalProcessControlConvertor.toProcessCO(entity));
|
||||||
}
|
}
|
||||||
|
|
@ -381,6 +382,8 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi {
|
||||||
Long orgId = project.getOrgId();
|
Long orgId = project.getOrgId();
|
||||||
List<EvalProjectFileCO> files = new java.util.ArrayList<>();
|
List<EvalProjectFileCO> files = new java.util.ArrayList<>();
|
||||||
|
|
||||||
|
// 风险分析/项目组-参与人签字(eval_risk_participant:risk_id 非空为风险分析,为空为项目组)
|
||||||
|
files.addAll(listRiskParticipantFiles(projectId));
|
||||||
// 业务合同-合同扫描件
|
// 业务合同-合同扫描件
|
||||||
files.addAll(evalContractQueryService.listProjectFiles(projectId, orgId));
|
files.addAll(evalContractQueryService.listProjectFiles(projectId, orgId));
|
||||||
// 现场踏勘-附件
|
// 现场踏勘-附件
|
||||||
|
|
@ -528,63 +531,115 @@ public class EvalProcessControlExecutor implements EvalProcessControlApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 归档时将 listProjectFiles 查询出的所有项目文件以 ARCHIVED 资料类型合并写入 eval_project_doc.project_doc_url。
|
* 归档项目资料:将 listProjectFiles 查询出的所有项目文件写入 eval_project_archive_file(来源:流程自动记录)。
|
||||||
* 写入前先移除原有 materialType=ARCHIVED 的记录,再追加本次归档的文件后更新。
|
* 写入前先删除该项目 record_source=auto_process_record 的旧记录,再逐文件构建新增数据。
|
||||||
*/
|
*/
|
||||||
private void upsertArchivedProjectDocs(Long projectId, EvalProjectEntity project) {
|
private void saveAutoArchiveFiles(Long projectId, EvalProjectEntity project) {
|
||||||
List<EvalProjectFileCO> files = listProjectFiles(projectId).getData();
|
// 先删除该项目流程自动记录来源的旧档案文件,避免重复归档产生脏数据
|
||||||
// 将每个文件 projectDocUrl 中的 JSON 数组扁平化:数组内每个文件对象拆分为独立的资料条目
|
evalProjectArchiveFileMapper.delete(new LambdaQueryWrapper<EvalProjectArchiveFileDO>()
|
||||||
List<EvalProjectDocMaterialItemCO> archivedItems = new ArrayList<>();
|
.eq(EvalProjectArchiveFileDO::getProjectId, String.valueOf(projectId))
|
||||||
if (!CollectionUtils.isEmpty(files)) {
|
.eq(EvalProjectArchiveFileDO::getRecordSource, ProjectArchiveFileSourceEnum.AUTO_PROCESS_RECORD.getCode()));
|
||||||
for (EvalProjectFileCO f : files) {
|
|
||||||
List<JSONObject> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EvalProjectDocDO docDO = evalProjectDocMapper.selectOne(new LambdaQueryWrapper<EvalProjectDocDO>()
|
List<EvalProjectFileCO> files = listProjectFiles(projectId).getData();
|
||||||
.select(EvalProjectDocDO::getId, EvalProjectDocDO::getProjectDocUrl)
|
if (CollectionUtils.isEmpty(files)) {
|
||||||
.eq(EvalProjectDocDO::getProjectId, projectId));
|
return;
|
||||||
if (docDO == null) {
|
|
||||||
EvalCustomerDO evalCustomerDO = evalCustomerMapper.selectOne(new LambdaQueryWrapper<EvalCustomerDO>()
|
|
||||||
.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<EvalProjectDocMaterialItemCO> existing = new ArrayList<>();
|
|
||||||
if (StringUtils.hasText(docDO.getProjectDocUrl())) {
|
|
||||||
List<EvalProjectDocMaterialItemCO> 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<EvalProjectDocDO>()
|
|
||||||
.eq(EvalProjectDocDO::getId, docDO.getId())
|
|
||||||
.set(EvalProjectDocDO::getProjectDocUrl, JSON.toJSONString(existing)));
|
|
||||||
}
|
}
|
||||||
|
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<EvalProjectFileCO> listRiskParticipantFiles(Long projectId) {
|
||||||
|
List<EvalProjectFileCO> files = new ArrayList<>();
|
||||||
|
List<EvalRiskParticipantDO> participants = evalRiskParticipantMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<EvalRiskParticipantDO>()
|
||||||
|
.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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import lombok.Data;
|
||||||
import org.qinan.safetyeval.domain.constant.ArchiveTypeEnum;
|
import org.qinan.safetyeval.domain.constant.ArchiveTypeEnum;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,47 +18,34 @@ import java.io.Serializable;
|
||||||
public class EvalProjectArchiveFileAddCmd implements Serializable {
|
public class EvalProjectArchiveFileAddCmd implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
|
||||||
* 项目ID
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = "项目ID", required = true)
|
@ApiModelProperty(value = "项目ID", required = true)
|
||||||
@NotBlank(message = "项目ID不能为空")
|
@NotBlank(message = "项目ID不能为空")
|
||||||
private String projectId;
|
private String projectId;
|
||||||
/**
|
|
||||||
* 文件地址
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = "文件地址", required = true)
|
@ApiModelProperty(value = "文件地址", required = true)
|
||||||
@NotBlank(message = "文件地址不能为空")
|
@NotBlank(message = "文件地址不能为空")
|
||||||
private String fileUrl;
|
private String fileUrl;
|
||||||
/**
|
|
||||||
* 文件名称
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = "文件名称", required = true)
|
@ApiModelProperty(value = "文件名称", required = true)
|
||||||
@NotBlank(message = "文件名称不能为空")
|
@Size(max = 100, message = "文件名称长度不能超过100")
|
||||||
private String fileName;
|
private String fileName;
|
||||||
/**
|
|
||||||
* ArchiveTypeEnum.REMARKS
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = ArchiveTypeEnum.REMARKS, required = true)
|
@ApiModelProperty(value = ArchiveTypeEnum.REMARKS, required = true)
|
||||||
@NotBlank(message = ArchiveTypeEnum.REMARKS + "不能为空")
|
@NotBlank(message = ArchiveTypeEnum.REMARKS + "不能为空")
|
||||||
|
@Size(max = 100, message = "档案类型长度不能超过100")
|
||||||
private String archiveType;
|
private String archiveType;
|
||||||
|
|
||||||
/**
|
|
||||||
* 业务节点
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = "业务节点", required = true)
|
@ApiModelProperty(value = "业务节点", required = true)
|
||||||
@NotBlank(message = "业务节点不能为空")
|
@NotBlank(message = "业务节点不能为空")
|
||||||
|
@Size(max = 32, message = "业务节点长度不能超过32")
|
||||||
private String businessNode;
|
private String businessNode;
|
||||||
/**
|
|
||||||
* 来源 auto_process_record流程自动记录,upload_additional_files 补充上传
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传", required = true)
|
@ApiModelProperty(value = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传", required = true)
|
||||||
@NotBlank(message = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传不能为空")
|
@NotBlank(message = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传不能为空")
|
||||||
|
@Size(max = 32, message = "来源长度不能超过32")
|
||||||
private String recordSource;
|
private String recordSource;
|
||||||
/**
|
|
||||||
* 环境
|
|
||||||
*/
|
|
||||||
@ApiModelProperty(value = "环境")
|
|
||||||
private String env;
|
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
@Size(max = 200, message = "备注长度不能超过200")
|
||||||
|
private String remarks;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import org.qinan.safetyeval.domain.constant.ArchiveTypeEnum;
|
||||||
|
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -56,4 +57,8 @@ public class EvalProjectArchiveFileUpdateCmd implements Serializable {
|
||||||
@ApiModelProperty(value = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传", required = true)
|
@ApiModelProperty(value = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传", required = true)
|
||||||
@NotBlank(message = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传不能为空")
|
@NotBlank(message = "来源 auto_process_record流程自动记录,upload_additional_files 补充上传不能为空")
|
||||||
private String recordSource;
|
private String recordSource;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
@Size(max = 200, message = "备注长度不能超过200")
|
||||||
|
private String remarks;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,7 @@ public class EvalProjectArchiveFileCo extends ClientObject {
|
||||||
|
|
||||||
@ApiModelProperty(value = "创建人")
|
@ApiModelProperty(value = "创建人")
|
||||||
protected String createName;
|
protected String createName;
|
||||||
|
|
||||||
|
@ApiModelProperty(value = "备注")
|
||||||
|
private String remarks;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue