diff --git a/.gitignore b/.gitignore
index bc7e164d..b6c9870f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -78,3 +78,5 @@
/outbridge/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
/outbridge/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
/outbridge/target/outbridge-0.0.1-SNAPSHOT.jar
+/.cursor/rules/1.mdc
+/.trae/rules/1.md
diff --git a/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java b/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java
index 45b1c545..a62d91be 100644
--- a/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java
+++ b/data/src/main/java/com/sdm/data/service/impl/MinioFileIDataFileServiceImpl.java
@@ -2642,60 +2642,74 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
fileMetadataInfoService.updateById(fileMetadataInfo);
}
+
/**
- * 上传文件并更新元数据。
- * @param req
- * @param oldFileMetadataInfo
- * @param versionNo
- * @param fileGroupId
- * @param dirMetadataInfo
+ * 覆盖上传新文件(鸠占鹊巢):保持主记录 ID 不变,同时保留历史版本。
+ *
+ * 最小方案约束:
+ * 1) 仅保留“文件内容 + 主元数据”的历史版本;标签/工况/扩展信息始终以最新为准,不做历史克隆;
+ * 2) 上传的新文件使用新的 objectKey(带版本号后缀),避免覆盖 MinIO 旧对象。
+ *
*/
- public void uploadAndUpdateFile(UpdateFileReq req, FileMetadataInfo oldFileMetadataInfo, Long versionNo, Long fileGroupId,FileMetadataInfo dirMetadataInfo) {
+ public void uploadAndUpdateFile(UpdateFileReq req, FileMetadataInfo oldFileMetadataInfo, Long versionNo, Long fileGroupId, FileMetadataInfo dirMetadataInfo) {
String newFileMinioObjectKey = "";
try {
- // 保留历史文件版本,新增一条文件版本记录
+ // 1) 备份:克隆当前主记录为历史行(新 ID),用于版本回溯
+ FileMetadataInfo historyFileInfo = new FileMetadataInfo();
+ BeanUtils.copyProperties(oldFileMetadataInfo, historyFileInfo);
+ historyFileInfo.setId(null);
+ historyFileInfo.setTempMetadata(null);
+ historyFileInfo.setIsLatest(false);
+ fileMetadataInfoService.save(historyFileInfo);
+
+ // 2) 生成新版本文件名与 objectKey
String originalName = req.getFileName();
String versionSuffix = "_V" + (versionNo + 1);
- String modifiedFileName;
-
int dotIndex = originalName.lastIndexOf('.');
- if (dotIndex != -1) {
- // 如果文件有后缀,则在文件名和后缀之间插入版本号
- modifiedFileName = originalName.substring(0, dotIndex) + versionSuffix + originalName.substring(dotIndex);
- } else {
- // 如果文件没有后缀,报错
+ if (dotIndex == -1) {
log.error("文件没有后缀");
throw new RuntimeException("文件没有后缀");
}
+ String modifiedFileName = originalName.substring(0, dotIndex) + versionSuffix + originalName.substring(dotIndex);
- // 新文件名 modifiedFileName = newFile_V2.txt ,处理历史版本 oldFileMinioObjectKey= a/b/c/oldFile_V1.txt originalName=oldFile.txt , 替换为 newFileMinioObjectKey= a/b/c/test1_V2.txt
String parDirObjectKey = dirMetadataInfo.getObjectKey();
newFileMinioObjectKey = getFileMinioObjectKey(parDirObjectKey + modifiedFileName);
- minioService.uploadFile(req.getFile(), newFileMinioObjectKey, null,oldFileMetadataInfo.getBucketName());
- // 创建目录元数据并保存到数据库
- FileMetadataInfo newFileInfo = createFileMetadata(newFileMinioObjectKey, req.getFileName(),
- req.getProjectId(), req.getAnalysisDirectionId(), req.getRemarks(), oldFileMetadataInfo.getParentId(), req.getFile().getSize(), null
- );
- newFileInfo.setRemarks(oldFileMetadataInfo.getRemarks());
- newFileInfo.setProjectId(oldFileMetadataInfo.getProjectId());
- newFileInfo.setAnalysisDirectionName(oldFileMetadataInfo.getAnalysisDirectionName());
- newFileInfo.setFileGroupId(fileGroupId);
- newFileInfo.setVersionNo(versionNo + 1);
+ // 3) 上传新文件
+ minioService.uploadFile(req.getFile(), newFileMinioObjectKey, null, oldFileMetadataInfo.getBucketName());
- fileMetadataInfoService.save(newFileInfo);
+ // 4) 原地更新:主记录 ID 不变,指向最新版本
+ oldFileMetadataInfo.setObjectKey(newFileMinioObjectKey);
+ oldFileMetadataInfo.setOriginalName(req.getFileName());
+ oldFileMetadataInfo.setFileSize(req.getFile().getSize());
+ oldFileMetadataInfo.setVersionNo(versionNo + 1);
+ oldFileMetadataInfo.setFileGroupId(fileGroupId);
+ oldFileMetadataInfo.setIsLatest(true);
+ oldFileMetadataInfo.setUpdateTime(LocalDateTime.now());
+ oldFileMetadataInfo.setUpdaterId(ThreadLocalContext.getUserId());
- // 创建文件标签关系(如果有)
+ // 同步本次更新的元数据字段
+ oldFileMetadataInfo.setRemarks(req.getRemarks());
+ oldFileMetadataInfo.setProjectId(req.getProjectId());
+ oldFileMetadataInfo.setAnalysisDirectionId(req.getAnalysisDirectionId());
+ oldFileMetadataInfo.setFileType(req.getFileType());
+
+ fileMetadataInfoService.updateById(oldFileMetadataInfo);
+
+ // 5) 更新关联(仅更新主记录关联,不做历史克隆)
if (CollectionUtils.isNotEmpty(req.getDictTags())) {
- updateFileTags(req, newFileInfo, dirMetadataInfo);
+ updateFileTags(req, oldFileMetadataInfo, dirMetadataInfo);
}
- //绑定文件和工况库的关系
if (CollectionUtils.isNotEmpty(req.getSimulationPoolInfoList())) {
for (SimulationPoolInfo simulationPoolInfo : req.getSimulationPoolInfoList()) {
+ fileSimulationMappingService.lambdaUpdate()
+ .eq (FileSimulationMapping::getSimulationPoolId, oldFileMetadataInfo.getId())
+ .eq (FileSimulationMapping::getSimulationPoolVersion, simulationPoolInfo.getSimulationPoolVersion())
+ .eq(FileSimulationMapping::getFileId, oldFileMetadataInfo.getId()).remove();
for (String simulationPoolTaskId : simulationPoolInfo.getSimulationPoolTaskIds()) {
FileSimulationMapping fileSimulationMapping = new FileSimulationMapping();
- fileSimulationMapping.setFileId(newFileInfo.getId());
+ fileSimulationMapping.setFileId(oldFileMetadataInfo.getId());
fileSimulationMapping.setSimulationPoolId(simulationPoolInfo.getSimulationPoolId());
fileSimulationMapping.setSimulationPoolVersion(simulationPoolInfo.getSimulationPoolVersion());
fileSimulationMapping.setSimulationPoolTaskId(simulationPoolTaskId);
@@ -2704,84 +2718,61 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
}
}
- // 创建文件扩展信息并保存到数据库
- List fileMetadataExtensionList = new ArrayList<>();
+ // 扩展字段:作为“最新态”数据,覆盖更新主记录对应的扩展信息
List fileMetadataExtensionRequestList = req.getFileMetadataExtensionRequest();
if (fileMetadataExtensionRequestList != null && !fileMetadataExtensionRequestList.isEmpty()) {
+ fileMetadataExtensionService.lambdaUpdate().eq(FileMetadataExtension::getTFilemetaId, oldFileMetadataInfo.getId()).remove();
+ List fileMetadataExtensionList = new ArrayList<>();
fileMetadataExtensionRequestList.forEach(extensionRequest -> {
FileMetadataExtension fileMetadataExtension = new FileMetadataExtension();
- fileMetadataExtension.setTFilemetaId(newFileInfo.getId());
+ fileMetadataExtension.setTFilemetaId(oldFileMetadataInfo.getId());
fileMetadataExtension.setExtensionKey(extensionRequest.getExtensionKey());
fileMetadataExtension.setExtensionValue(extensionRequest.getExtensionValue());
- fileMetadataExtension.setDataType(Objects.toString(extensionRequest.getDataType(), "string")); // 默认为字符串类型,可根据需要调整
+ fileMetadataExtension.setDataType(Objects.toString(extensionRequest.getDataType(), "string"));
fileMetadataExtensionList.add(fileMetadataExtension);
});
- }
- fileMetadataExtensionService.saveBatch(fileMetadataExtensionList);
-
- // 循环查询当前文件每一级父目录id,并保存为一条file_storage,用户后续文件搜索统计
- Long parentDirId = dirMetadataInfo.getId();
- FileStorage fileStorage = new FileStorage();
-
- fileStorage.setFileId(newFileInfo.getId());
- fileStorage.setFileName(newFileInfo.getOriginalName());
- fileStorage.setUserId(ThreadLocalContext.getUserId());
- fileStorage.setTenantId(ThreadLocalContext.getTenantId());
- fileStorage.setFileBizType(newFileInfo.getFileType());
- // 文件后缀
- fileStorage.setFileSuffix(getSuffixWithoutDot(newFileInfo.getOriginalName()));
- fileStorage.setFileSize(req.getFile().getSize());
- while (parentDirId != null) {
- fileStorage.setId(null);
- fileStorage.setDirId(parentDirId);
- fileStorageService.save(fileStorage);
- parentDirId = fileMetadataInfoService.lambdaQuery().eq(FileMetadataInfo::getId, parentDirId).oneOpt()
- .map(FileMetadataInfo::getParentId)
- .orElse(null);
+ fileMetadataExtensionService.saveBatch(fileMetadataExtensionList);
}
- // 创建默认权限记录
- createFilePermission(newFileInfo.getId());
+ // FileStorage:只更新主记录 fileId 对应的统计信息,避免新增一堆重复统计
+ fileStorageService.lambdaUpdate()
+ .eq(FileStorage::getFileId, oldFileMetadataInfo.getId())
+ .set(FileStorage::getFileName, oldFileMetadataInfo.getOriginalName())
+ .set(FileStorage::getFileSize, oldFileMetadataInfo.getFileSize())
+ .set(FileStorage::getFileBizType, oldFileMetadataInfo.getFileType())
+ .update();
- // 需要审批的目录类型创建审批流
+ // 6) 审批:beforeData 使用备份历史行,afterData 使用更新后的主行
boolean isKnowledge = dirMetadataInfo != null && DirTypeEnum.isApprovalRequired(dirMetadataInfo.getDirType());
- // 需要审批的目录类型修改
- if(isKnowledge){
- // 新增的一条暂时不展示
- newFileInfo.setIsLatest(false);
- FileApproveRequestBuilder uploadAndUpdateFileApproveRequestBuilder = FileApproveRequestBuilder.builder()
- .toUpdateFileIds(List.of(newFileInfo.getId()))
+ if (isKnowledge) {
+ FileApproveRequestBuilder builder = FileApproveRequestBuilder.builder()
+ .toUpdateFileIds(List.of(oldFileMetadataInfo.getId()))
.contents(DirTypeEnum.buildApprovalTitle(dirMetadataInfo.getDirType(), "文件修改"))
.approveType(ApproveTypeEnum.KNOWLEDGE_APPROVE)
.approveFileActionENUM(ApproveFileActionENUM.MODIFY)
- .beforeData(List.of(oldFileMetadataInfo))
- .afterData(List.of(newFileInfo))
+ .beforeData(List.of(historyFileInfo))
+ .afterData(List.of(oldFileMetadataInfo))
.templateId(req.getTemplateId())
.templateName(req.getTemplateName())
.knowledgeBaseName(extractRelativePath(dirMetadataInfo))
.build();
- if(CollectionUtils.isNotEmpty(uploadAndUpdateFileApproveRequestBuilder.getBeforeData())){
- setCreatorNames(uploadAndUpdateFileApproveRequestBuilder.getBeforeData());
- setProjectName(uploadAndUpdateFileApproveRequestBuilder.getBeforeData());
- setAnalysisDirectionName(uploadAndUpdateFileApproveRequestBuilder.getBeforeData());
- setSimulationPoolAndTaskInfo(uploadAndUpdateFileApproveRequestBuilder.getBeforeData());
+
+ if (CollectionUtils.isNotEmpty(builder.getBeforeData())) {
+ setCreatorNames(builder.getBeforeData());
+ setProjectName(builder.getBeforeData());
+ setAnalysisDirectionName(builder.getBeforeData());
+ setSimulationPoolAndTaskInfo(builder.getBeforeData());
}
- // 只有修改有 afterData 值
- if (CollectionUtils.isNotEmpty(uploadAndUpdateFileApproveRequestBuilder.getAfterData())) {
- setCreatorNames(uploadAndUpdateFileApproveRequestBuilder.getAfterData());
- setProjectName(uploadAndUpdateFileApproveRequestBuilder.getAfterData());
- setAnalysisDirectionName(uploadAndUpdateFileApproveRequestBuilder.getAfterData());
- setSimulationPoolAndTaskInfo(uploadAndUpdateFileApproveRequestBuilder.getAfterData());
+ if (CollectionUtils.isNotEmpty(builder.getAfterData())) {
+ setCreatorNames(builder.getAfterData());
+ setProjectName(builder.getAfterData());
+ setAnalysisDirectionName(builder.getAfterData());
+ setSimulationPoolAndTaskInfo(builder.getAfterData());
}
- fileApproveExecutor.launchApproveAndUpdateStatus(uploadAndUpdateFileApproveRequestBuilder, ApproveFileDataTypeEnum.MODIFY_REVIEWING);
- }else {
- // 非知识库的,设置 历史版本 文件为非最新
- oldFileMetadataInfo.setIsLatest(false);
- fileMetadataInfoService.updateById(oldFileMetadataInfo);
+ fileApproveExecutor.launchApproveAndUpdateStatus(builder, ApproveFileDataTypeEnum.MODIFY_REVIEWING);
}
-
} catch (Exception e) {
minioService.deleteFile(newFileMinioObjectKey, oldFileMetadataInfo.getBucketName());
log.error("更新文件失败", e);
diff --git a/data/src/main/java/com/sdm/data/service/impl/dataFileHandle/ModifyFileApproveStrategy.java b/data/src/main/java/com/sdm/data/service/impl/dataFileHandle/ModifyFileApproveStrategy.java
index 7ebb04cc..258d813f 100644
--- a/data/src/main/java/com/sdm/data/service/impl/dataFileHandle/ModifyFileApproveStrategy.java
+++ b/data/src/main/java/com/sdm/data/service/impl/dataFileHandle/ModifyFileApproveStrategy.java
@@ -10,68 +10,75 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
+import java.util.List;
@Service
@Slf4j
public class ModifyFileApproveStrategy implements ApproveStrategy {
@Override
public boolean handle(ApproveContext context) {
-// FileMetadataInfo metadata = context.getApproveMetadataInfo();
- FileMetadataInfo metadata = context.getApproveMetadataInfos().get(0);
int status = context.getApproveStatus();
- IFileMetadataInfoService service = context.getFileMetadataInfoService();
IMinioService minioService = context.getMinioService();
+ IFileMetadataInfoService fileMetadataInfoService = context.getFileMetadataInfoService();
IFileMetadataExtensionService fileMetadataExtensionService = context.getFileMetadataExtensionService();
IFileUserPermissionService fileUserPermissionService = context.getFileUserPermissionService();
IFileStorageService fileStorageService = context.getFileStorageService();
IFileSimulationMappingService fileSimulationMappingService = context.getFileSimulationMappingService();
IFileTagRelService fileTagRelService = context.getFileTagRelService();
- // 最新的历史版本为
- FileMetadataInfo historyMetaData = service.lambdaQuery()
- .eq(FileMetadataInfo::getFileGroupId, metadata.getFileGroupId())
- // 当前老的还在生效的数据
- .eq(FileMetadataInfo::getIsLatest, true)
- .orderByDesc(FileMetadataInfo::getUpdateTime)
- .last("limit 1")
+ List metadataList = context.getApproveMetadataInfos();
+ if (metadataList == null || metadataList.isEmpty()) {
+ return false;
+ }
+
+ FileMetadataInfo mainMetadata = metadataList.get(0);
+
+ // 备份的历史记录(id 不同于主记录,且 group 相同,version减1查询)
+ FileMetadataInfo backupHistory = fileMetadataInfoService.lambdaQuery()
+ .eq(FileMetadataInfo::getFileGroupId, mainMetadata.getFileGroupId())
+ .eq(FileMetadataInfo::getVersionNo, mainMetadata.getVersionNo() - 1)
.one();
-
- // 审批通过
+ // 审批通过:主记录正式生效,备份行保留为历史版本(isLatest=false)
if (NumberConstants.TWO == status) {
- metadata.setApprovalStatus(ApprovalFileDataStatusEnum.APPROVED.getKey());
- metadata.setApproveType(ApproveFileDataTypeEnum.COMPLETED.getCode());
- // 设置成最新的文件
- metadata.setIsLatest(true);
- service.updateById(metadata);
- // 历史的设置成非最新
- if (historyMetaData != null) {
- historyMetaData.setIsLatest(false);
- service.updateById(historyMetaData);
+ mainMetadata.setApprovalStatus(ApprovalFileDataStatusEnum.APPROVED.getKey());
+ mainMetadata.setApproveType(ApproveFileDataTypeEnum.COMPLETED.getCode());
+ mainMetadata.setIsLatest(true);
+ fileMetadataInfoService.updateById(mainMetadata);
+
+ if (backupHistory != null) {
+ backupHistory.setIsLatest(false);
+ fileMetadataInfoService.updateById(backupHistory);
}
return true;
}
- // 审批不通过
+ // 审批不通过:回滚主记录,删除新 MinIO 对象和备份行
if (NumberConstants.THREE == status) {
- // 删除MinIO中修改的文件
- minioService.deleteFile(metadata.getObjectKey(), metadata.getBucketName());
- // 删除修改产生的新记录
- service.removeById(metadata.getId());
- fileMetadataExtensionService.remove(new LambdaQueryWrapper().eq(FileMetadataExtension::getTFilemetaId, metadata.getId()));
- fileUserPermissionService.remove(new LambdaQueryWrapper().eq(FileUserPermission::getTFilemetaId, metadata.getId()));
- fileStorageService.remove(new LambdaQueryWrapper().eq(FileStorage::getFileId, metadata.getId()));
- fileSimulationMappingService.remove(new LambdaQueryWrapper().eq(FileSimulationMapping::getFileId, metadata.getId()));
- // 删除文件标签关系
- fileTagRelService.remove(new LambdaQueryWrapper().eq(FileTagRel::getFileId, metadata.getId()));
+ // 1. 删除新上传的文件(主记录当前指向的 objectKey)
+ minioService.deleteFile(mainMetadata.getObjectKey(), mainMetadata.getBucketName());
+
+ // 2. 将主记录(ID 不变那个)回滚为备份行的数据
+ if (backupHistory != null) {
+ mainMetadata.setObjectKey(backupHistory.getObjectKey());
+ mainMetadata.setFileSize(backupHistory.getFileSize());
+ mainMetadata.setVersionNo(backupHistory.getVersionNo());
+ mainMetadata.setOriginalName(backupHistory.getOriginalName());
+ mainMetadata.setRemarks(backupHistory.getRemarks());
+ mainMetadata.setProjectId(backupHistory.getProjectId());
+ mainMetadata.setAnalysisDirectionId(backupHistory.getAnalysisDirectionId());
+ mainMetadata.setFileType(backupHistory.getFileType());
+ }
- if (historyMetaData != null) {
- historyMetaData.setTempMetadata(null);
- historyMetaData.setIsLatest(true);
- historyMetaData.setApprovalStatus(ApprovalFileDataStatusEnum.REJECTED.getKey());
- historyMetaData.setApproveType(ApproveFileDataTypeEnum.COMPLETED.getCode());
- historyMetaData.setUpdateTime(LocalDateTime.now());
- service.updateById(historyMetaData);
+ mainMetadata.setApprovalStatus(ApprovalFileDataStatusEnum.REJECTED.getKey());
+ mainMetadata.setApproveType(ApproveFileDataTypeEnum.COMPLETED.getCode());
+ mainMetadata.setIsLatest(true);
+ mainMetadata.setUpdateTime(LocalDateTime.now());
+ fileMetadataInfoService.updateById(mainMetadata);
+
+ // 3. 删除备份行(因为新版本已废弃,不需要保留这条历史备份)
+ if (backupHistory != null) {
+ fileMetadataInfoService.removeById(backupHistory.getId());
}
return true;
}