fix:数据总览,兼容同类型多级构建

This commit is contained in:
2026-03-04 10:05:16 +08:00
parent 55058a9333
commit 0e1f2d2b86
7 changed files with 177 additions and 90 deletions

View File

@@ -8,9 +8,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map;
@Data @Data
public class QueryBigFileReq extends BaseReq { public class QueryBigFileReq extends BaseReq {
@@ -22,7 +20,7 @@ public class QueryBigFileReq extends BaseReq {
/** /**
* 目录ID列表 * 目录ID列表
*/ */
private List<Long> dirIds = new ArrayList<>(); private Set<Long> dirIds = new HashSet<>();
/** /**
* 目录ID列表的大小用于 HAVING 子句 * 目录ID列表的大小用于 HAVING 子句

View File

@@ -68,7 +68,7 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
BeanUtils.copyProperties(getSimulationTaskFileReq, queryBigFileReq); BeanUtils.copyProperties(getSimulationTaskFileReq, queryBigFileReq);
// 步骤 1: 收集所有直接传入的 dirId // 步骤 1: 收集所有直接传入的 dirId
List<Long> allDirIds = new ArrayList<>(); Set<Long> allDirIds = new HashSet<>();
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getProjectDirIds())) { if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getProjectDirIds())) {
allDirIds.addAll(getSimulationTaskFileReq.getProjectDirIds()); allDirIds.addAll(getSimulationTaskFileReq.getProjectDirIds());
} }

View File

@@ -554,7 +554,7 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
} }
Long tenantId = ThreadLocalContext.getTenantId(); Long tenantId = ThreadLocalContext.getTenantId();
List<Long> dirIds = CollectionUtils.isEmpty(queryBigFileReq.getDirIds()) ? null : queryBigFileReq.getDirIds(); Set<Long> dirIds = CollectionUtils.isEmpty(queryBigFileReq.getDirIds()) ? null : queryBigFileReq.getDirIds();
// 查询符合标签的文件id // 查询符合标签的文件id
return fileTagRelService.lambdaQuery() return fileTagRelService.lambdaQuery()

View File

@@ -26,6 +26,7 @@ import com.sdm.common.entity.resp.system.CIDUserResp;
import com.sdm.common.feign.impl.project.SimulationNodeFeignClientImpl; import com.sdm.common.feign.impl.project.SimulationNodeFeignClientImpl;
import com.sdm.common.feign.impl.system.SysUserFeignClientImpl; import com.sdm.common.feign.impl.system.SysUserFeignClientImpl;
import com.sdm.common.feign.inter.project.ISimulationTaskFeignClient; import com.sdm.common.feign.inter.project.ISimulationTaskFeignClient;
import com.sdm.common.service.TagMapService;
import com.sdm.common.utils.CidSysUserUtil; import com.sdm.common.utils.CidSysUserUtil;
import com.sdm.common.utils.PageUtils; import com.sdm.common.utils.PageUtils;
import com.sdm.data.convert.FileMetadataConvert; import com.sdm.data.convert.FileMetadataConvert;
@@ -87,6 +88,10 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
@Autowired @Autowired
private ISimulationTaskFeignClient simulationTaskFeignClient; private ISimulationTaskFeignClient simulationTaskFeignClient;
@Autowired
private TagMapService tagMapService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public SdmResponse saveDimensionTemplateWithHierarchies(TemplateCreationRequest request) { public SdmResponse saveDimensionTemplateWithHierarchies(TemplateCreationRequest request) {
@@ -237,22 +242,21 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
List<String> chooseUuids = nodeDirInfos.stream().map(FileMetadataInfo::getRelatedResourceUuid).toList(); List<String> chooseUuids = nodeDirInfos.stream().map(FileMetadataInfo::getRelatedResourceUuid).toList();
// chooseUuid和chooseNodeType不为空,并且是node节点类型才是节点文件夹才需要查询子节点文件夹文件 // chooseUuid和chooseNodeType不为空,并且是node节点类型才是节点文件夹才需要查询子节点文件夹文件
if (ObjectUtils.isNotEmpty(chooseUuids) && ObjectUtils.isNotEmpty(chooseNodeType) && NodeTypeEnum.isNodeType(chooseNodeType)) { Map<String, String> tagMap = tagMapService.getTagMapName();
if (ObjectUtils.isNotEmpty(chooseUuids) && ObjectUtils.isNotEmpty(chooseNodeType) && tagMap.containsKey(chooseNodeType)) {
// 从dimensionNodeTyepOrderList中获取chooseNodeType下一个位置的数据有可能chooseNodeType所在位置就是最后一层节点,SdmResponse返回空数据 // 从dimensionNodeTyepOrderList中获取chooseNodeType下一个位置的数据有可能chooseNodeType所在位置就是最后一层节点,SdmResponse返回空数据
int index = dimensionNodeTyepOrderList.indexOf(chooseNodeType); int index = dimensionNodeTyepOrderList.indexOf(chooseNodeType);
if (index == -1) { if (index == -1) {
return SdmResponse.failed("选中节点类型不在数据展示维度中"); return SdmResponse.failed("选中节点类型不在数据展示维度中");
} }
// 判断是否是最后一层节点,如果是最后一层节点,则不需要查询子节点文件 // 非最后一层:查模板下一层;最后一层:查同类型连续子节点(例如 分类->分类)
if (index != dimensionNodeTyepOrderList.size() - 1) { String nextNodeType = (index != dimensionNodeTyepOrderList.size() - 1)
// 获取dimensionNodeTyepOrderList的index+1位置的节点类型 ? dimensionNodeTyepOrderList.get(index + 1)
String nextNodeType = dimensionNodeTyepOrderList.get(index + 1); : chooseNodeType;
SdmResponse<List<AllNodeByProjectIdAndTypeResp>> allNodeByProjectIdAndType = simuluationNodeFeignClient.getAllNodeByProjectIdAndType(chooseUuids, nextNodeType); SdmResponse<List<AllNodeByProjectIdAndTypeResp>> allNodeByProjectIdAndType = simuluationNodeFeignClient.getAllNodeByProjectIdAndType(chooseUuids, nextNodeType);
if (allNodeByProjectIdAndType.isSuccess() && ObjectUtils.isNotEmpty(allNodeByProjectIdAndType.getData())) { if (allNodeByProjectIdAndType.isSuccess() && ObjectUtils.isNotEmpty(allNodeByProjectIdAndType.getData())) {
uuids.addAll(allNodeByProjectIdAndType.getData().stream().map(AllNodeByProjectIdAndTypeResp::getUuid).toList()); uuids.addAll(allNodeByProjectIdAndType.getData().stream().map(AllNodeByProjectIdAndTypeResp::getUuid).toList());
}
} }
} }

View File

@@ -833,7 +833,7 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
QueryBigFileReq queryBigFileReq = new QueryBigFileReq(); QueryBigFileReq queryBigFileReq = new QueryBigFileReq();
List<Long> dirIds = new ArrayList<>(); Set<Long> dirIds = new HashSet<>();
Integer dirType; Integer dirType;
if (ObjectUtils.isNotEmpty(minioFileSearchReq.getParentUuid())) { if (ObjectUtils.isNotEmpty(minioFileSearchReq.getParentUuid())) {
// 项目节点下搜索文件 // 项目节点下搜索文件

View File

@@ -179,7 +179,6 @@ public class MapperCompatibilityTest {
void testFileStorageMapperSelectBigFiles() { void testFileStorageMapperSelectBigFiles() {
QueryBigFileReq req = new QueryBigFileReq(); QueryBigFileReq req = new QueryBigFileReq();
req.setIsLatest(true); req.setIsLatest(true);
req.setDirIds(Arrays.asList(1L));
List<FileStorage> result = fileStorageMapper.selectBigFiles(req, 1000L, 1L); List<FileStorage> result = fileStorageMapper.selectBigFiles(req, 1000L, 1L);
assertNotNull(result); assertNotNull(result);

View File

@@ -2293,94 +2293,180 @@ public class NodeServiceImpl extends ServiceImpl<SimulationNodeMapper, Simulatio
@Override @Override
public SdmResponse<List<AllNodeByProjectIdAndTypeResp>> getAllNodeByProjectIdAndType(List<String> uuids, String nextNodeType) { public SdmResponse<List<AllNodeByProjectIdAndTypeResp>> getAllNodeByProjectIdAndType(List<String> uuids, String nextNodeType) {
Map<String, String> TagMap = tagMapService.getTagMapName(); if (CollectionUtils.isEmpty(uuids) || StringUtils.isBlank(nextNodeType)) {
if ( ObjectUtils.isEmpty(TagMap)) { return SdmResponse.success();
}
Map<String, String> tagMap = tagMapService.getTagMapName();
if (ObjectUtils.isEmpty(tagMap)) {
log.error("字典信息查询失败"); log.error("字典信息查询失败");
return SdmResponse.success(); return SdmResponse.success();
} }
Optional<SimulationNode> simulationNodeOptional = this.lambdaQuery().in(SimulationNode::getUuid, uuids).list().stream().findFirst(); List<SimulationNode> currentNodes = this.lambdaQuery()
if (!simulationNodeOptional.isPresent()) { .in(SimulationNode::getUuid, uuids)
.list();
if (CollectionUtils.isEmpty(currentNodes)) {
return SdmResponse.failed("未找到节点"); return SdmResponse.failed("未找到节点");
} }
SimulationNode currentNode = simulationNodeOptional.get(); SimulationNode currentNode = currentNodes.get(0);
String currentNodeType = currentNode.getNodeType(); String currentNodeType = currentNode.getNodeType();
String currentNodeTag = TagMap.get(currentNodeType);
String nextNodeTag = TagMap.get(nextNodeType); // 先查当前节点下是否存在同类型直接子节点(连续同类型场景)
List<SimulationNode> sameTypeChildren = this.lambdaQuery()
// 当前节点向前搜索 .in(SimulationNode::getParentId, uuids)
List<String> preUUids = this.lambdaQuery() .eq(SimulationNode::getNodeType, currentNodeType)
.in(TagConstant.TAG1.equals(currentNodeTag), SimulationNode::getTag1, uuids)
.in(TagConstant.TAG2.equals(currentNodeTag), SimulationNode::getTag2, uuids)
.in(TagConstant.TAG3.equals(currentNodeTag), SimulationNode::getTag3, uuids)
.in(TagConstant.TAG4.equals(currentNodeTag), SimulationNode::getTag4, uuids)
.in(TagConstant.TAG5.equals(currentNodeTag), SimulationNode::getTag5, uuids)
.in(TagConstant.TAG6.equals(currentNodeTag), SimulationNode::getTag6, uuids)
.in(TagConstant.TAG7.equals(currentNodeTag), SimulationNode::getTag7, uuids)
.in(TagConstant.TAG8.equals(currentNodeTag), SimulationNode::getTag8, uuids)
.in(TagConstant.TAG9.equals(currentNodeTag), SimulationNode::getTag9, uuids)
.in(TagConstant.TAG10.equals(currentNodeTag), SimulationNode::getTag10, uuids)
.orderByDesc(SimulationNode::getCreateTime)
.list().stream().map(simulationNode -> {
if (TagConstant.TAG1.equals(nextNodeTag)) {
return simulationNode.getTag1();
} else if (TagConstant.TAG2.equals(nextNodeTag)) {
return simulationNode.getTag2();
} else if (TagConstant.TAG3.equals(nextNodeTag)) {
return simulationNode.getTag3();
} else if (TagConstant.TAG4.equals(nextNodeTag)) {
return simulationNode.getTag4();
} else if (TagConstant.TAG5.equals(nextNodeTag)) {
return simulationNode.getTag5();
} else if (TagConstant.TAG6.equals(nextNodeTag)) {
return simulationNode.getTag6();
} else if (TagConstant.TAG7.equals(nextNodeTag)) {
return simulationNode.getTag7();
} else if (TagConstant.TAG8.equals(nextNodeTag)) {
return simulationNode.getTag8();
} else if (TagConstant.TAG9.equals(nextNodeTag)) {
return simulationNode.getTag9();
} else if (TagConstant.TAG10.equals(nextNodeTag)) {
return simulationNode.getTag10();
} else {
return null;
}
}
).toList();
List<SimulationNode> preSimulationNodeList = this.lambdaQuery().in(SimulationNode::getUuid, preUUids).list();
// 当前节点向后搜索
List<SimulationNode> simulationNodeList = this.lambdaQuery()
.in(TagConstant.TAG1.equals(currentNodeTag), SimulationNode::getTag1, uuids)
.in(TagConstant.TAG2.equals(currentNodeTag), SimulationNode::getTag2, uuids)
.in(TagConstant.TAG3.equals(currentNodeTag), SimulationNode::getTag3, uuids)
.in(TagConstant.TAG4.equals(currentNodeTag), SimulationNode::getTag4, uuids)
.in(TagConstant.TAG5.equals(currentNodeTag), SimulationNode::getTag5, uuids)
.in(TagConstant.TAG6.equals(currentNodeTag), SimulationNode::getTag6, uuids)
.in(TagConstant.TAG7.equals(currentNodeTag), SimulationNode::getTag7, uuids)
.in(TagConstant.TAG8.equals(currentNodeTag), SimulationNode::getTag8, uuids)
.in(TagConstant.TAG9.equals(currentNodeTag), SimulationNode::getTag9, uuids)
.in(TagConstant.TAG10.equals(currentNodeTag), SimulationNode::getTag10, uuids)
.eq(SimulationNode::getNodeType, nextNodeType)
.orderByDesc(SimulationNode::getCreateTime) .orderByDesc(SimulationNode::getCreateTime)
.list(); .list();
log.info("getAllNodeByProjectIdAndType sameTypeChildren size:{}, currentNodeType:{}, inputUuidsSize:{}",
sameTypeChildren.size(), currentNodeType, uuids.size());
Set<String> matchedParentUuids = sameTypeChildren.stream()
.map(SimulationNode::getParentId)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
List<String> remainingUuids = uuids.stream()
.filter(uuid -> !matchedParentUuids.contains(uuid))
.toList();
log.info("getAllNodeByProjectIdAndType remainingUuids size:{}, matchedParentUuids size:{}",
remainingUuids.size(), matchedParentUuids.size());
List<SimulationNode> simulationNodeList = new ArrayList<>(sameTypeChildren);
// 当 nextNodeType 与 currentNodeType 相同(最后一层继续同类型下钻)时,
// 仅允许返回直接子节点,禁止对 remainingUuids 走 tag 链路查询,避免引入平级数据。
if (StringUtils.equals(currentNodeType, nextNodeType)) {
if (CollectionUtils.isEmpty(simulationNodeList)) {
return SdmResponse.success();
}
return SdmResponse.success(buildNodeRespList(simulationNodeList));
}
if (CollectionUtils.isNotEmpty(remainingUuids)) {
String currentNodeTag = tagMap.get(currentNodeType);
String nextNodeTag = tagMap.get(nextNodeType);
if (StringUtils.isBlank(currentNodeTag) || StringUtils.isBlank(nextNodeTag)) {
log.error("节点类型未配置tag映射,currentNodeType:{},nextNodeType:{}", currentNodeType, nextNodeType);
if (CollectionUtils.isEmpty(simulationNodeList)) {
return SdmResponse.success();
}
} else {
// 规则1剩余节点不能直接拿uuid去匹配tag必须先取出当前层对应的tag值兼容tag链路逗号拼接
List<String> currentTagValues = extractTagValuesByNodeTag(currentNodes, remainingUuids, currentNodeTag);
if (CollectionUtils.isEmpty(currentTagValues)) {
log.info("getAllNodeByProjectIdAndType currentTagValues empty, currentNodeTag:{}, remainingUuidsSize:{}",
currentNodeTag, remainingUuids.size());
} else {
// 规则2按当前层tag值定位同链路节点再映射到下一层tag值并反查uuid
List<SimulationNode> matchedChainNodes = queryNodesByCurrentTagValues(currentNodeTag, currentTagValues);
List<String> preUUids = matchedChainNodes.stream()
.map(simulationNode -> resolveTagValue(simulationNode, nextNodeTag))
.filter(StringUtils::isNotBlank)
.map(tag-> {
return tag.split(",")[0];
})
.toList();
List<SimulationNode> preSimulationNodeList = CollectionUtils.isEmpty(preUUids)
? Collections.emptyList()
: this.lambdaQuery().in(SimulationNode::getUuid, preUUids).list();
simulationNodeList.addAll(preSimulationNodeList);
// 规则3同时保留原有“按nextNodeType正向查下一层”能力
/* List<SimulationNode> nextTypeNodeList = matchedChainNodes.stream()
.filter(node -> StringUtils.equals(node.getNodeType(), nextNodeType))
.toList();
simulationNodeList.addAll(nextTypeNodeList);
*/
log.info("getAllNodeByProjectIdAndType matchedChainNodes size:{}, nextNodeType:{}",
matchedChainNodes.size(), nextNodeType);
}
}
}
simulationNodeList.addAll(preSimulationNodeList);
if (CollectionUtils.isEmpty(simulationNodeList)) { if (CollectionUtils.isEmpty(simulationNodeList)) {
return SdmResponse.success(); return SdmResponse.success();
} }
List<AllNodeByProjectIdAndTypeResp> allNodeByProjectIdAndTypeRespList = new ArrayList<>();
simulationNodeList.forEach(simulationNode -> {
AllNodeByProjectIdAndTypeResp allNodeByProjectIdAndTypeResp = new AllNodeByProjectIdAndTypeResp();
BeanUtils.copyProperties(simulationNode, allNodeByProjectIdAndTypeResp);
allNodeByProjectIdAndTypeResp.setId(simulationNode.getId().longValue());
allNodeByProjectIdAndTypeRespList.add(allNodeByProjectIdAndTypeResp);
});
return SdmResponse.success(allNodeByProjectIdAndTypeRespList); return SdmResponse.success(buildNodeRespList(simulationNodeList));
}
/**
* 根据当前节点类型对应的tag位从当前节点集合中提取tag值。
* 说明:
* 1) 这里只从 remainingUuids 对应节点提取,避免混入已命中同类型子节点的父节点;
* 2) 提取的是 tag 字段值,不是 uuid兼容 tag4 这类“逗号拼接链路”场景;
* 3) 统一去空和去重,减少后续 in 查询的数据量。
*/
private List<String> extractTagValuesByNodeTag(List<SimulationNode> currentNodes, List<String> remainingUuids, String currentNodeTag) {
return currentNodes.stream()
.filter(node -> remainingUuids.contains(node.getUuid()))
.map(node -> resolveTagValue(node, currentNodeTag))
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
}
/**
* 按“当前层tag值”查询同链路节点。
* 规则tag字段存的是层级链路值因此这里必须用 tag 值匹配,不使用 uuid 直接匹配 tag 字段。
*/
private List<SimulationNode> queryNodesByCurrentTagValues(String currentNodeTag, List<String> currentTagValues) {
return this.lambdaQuery()
.in(TagConstant.TAG1.equals(currentNodeTag), SimulationNode::getTag1, currentTagValues)
.in(TagConstant.TAG2.equals(currentNodeTag), SimulationNode::getTag2, currentTagValues)
.in(TagConstant.TAG3.equals(currentNodeTag), SimulationNode::getTag3, currentTagValues)
.in(TagConstant.TAG4.equals(currentNodeTag), SimulationNode::getTag4, currentTagValues)
.in(TagConstant.TAG5.equals(currentNodeTag), SimulationNode::getTag5, currentTagValues)
.in(TagConstant.TAG6.equals(currentNodeTag), SimulationNode::getTag6, currentTagValues)
.in(TagConstant.TAG7.equals(currentNodeTag), SimulationNode::getTag7, currentTagValues)
.in(TagConstant.TAG8.equals(currentNodeTag), SimulationNode::getTag8, currentTagValues)
.in(TagConstant.TAG9.equals(currentNodeTag), SimulationNode::getTag9, currentTagValues)
.in(TagConstant.TAG10.equals(currentNodeTag), SimulationNode::getTag10, currentTagValues)
.list();
}
/**
* 按 tag 位读取节点的 tag 值。
*/
private String resolveTagValue(SimulationNode node, String tag) {
if (TagConstant.TAG1.equals(tag)) {
return node.getTag1();
} else if (TagConstant.TAG2.equals(tag)) {
return node.getTag2();
} else if (TagConstant.TAG3.equals(tag)) {
return node.getTag3();
} else if (TagConstant.TAG4.equals(tag)) {
return node.getTag4();
} else if (TagConstant.TAG5.equals(tag)) {
return node.getTag5();
} else if (TagConstant.TAG6.equals(tag)) {
return node.getTag6();
} else if (TagConstant.TAG7.equals(tag)) {
return node.getTag7();
} else if (TagConstant.TAG8.equals(tag)) {
return node.getTag8();
} else if (TagConstant.TAG9.equals(tag)) {
return node.getTag9();
} else if (TagConstant.TAG10.equals(tag)) {
return node.getTag10();
}
return null;
}
/**
* 将节点列表转为响应对象并按 uuid 去重,避免多路径合并导致重复。
*/
private List<AllNodeByProjectIdAndTypeResp> buildNodeRespList(List<SimulationNode> simulationNodeList) {
return simulationNodeList.stream()
.collect(Collectors.toMap(SimulationNode::getUuid, Function.identity(), (a, b) -> a, LinkedHashMap::new))
.values().stream().map(simulationNode -> {
AllNodeByProjectIdAndTypeResp resp = new AllNodeByProjectIdAndTypeResp();
BeanUtils.copyProperties(simulationNode, resp);
resp.setId(simulationNode.getId().longValue());
return resp;
}).toList();
} }
@Override @Override