fix:数据总览,任务按照维度配置,计算挂在最深路径

This commit is contained in:
2026-04-01 17:19:08 +08:00
parent 7ac9eb30a3
commit e84a453b19
7 changed files with 205 additions and 59 deletions

View File

@@ -37,7 +37,7 @@ public class DimensionTemplateHierarchy implements Serializable {
@TableField("templateId")
private Long templateId;
@Schema(description = "显示名称:tag1,tag2,tag3...tag10")
@Schema(description = "显示名称:project,pahse,machine")
@TableField("displayName")
private String displayName;

View File

@@ -1,5 +1,6 @@
package com.sdm.data.model.req;
import com.sdm.common.entity.req.data.TagReq;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.NotEmpty;
@@ -25,4 +26,7 @@ public class GetSimulationNodeTreeReq {
*/
@Schema(description = "项目名称/编码关键字")
private String keyword;
@Schema(description = "标签查询条件")
private TagReq tagReq;
}

View File

@@ -1,6 +1,7 @@
package com.sdm.data.model.req;
import com.sdm.common.entity.req.data.BaseReq;
import com.sdm.common.entity.req.data.TagReq;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.NotEmpty;
@@ -38,4 +39,7 @@ public class ListSimulationNodeTreeReq extends BaseReq {
*/
@Schema(description = "是否开启作业模式")
boolean jobMode=false;
@Schema(description = "标签查询条件")
private TagReq tagReq;
}

View File

@@ -337,7 +337,7 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
if (i > 0) {
q.or();
}
q.eq(column, value).or().likeLeft(column, "," + value);
q.eq(column, value).or().likeLeft(column, "," + value).or().likeRight(column, value + ",").or().like(column, "," + value + ",");
}
});
}

View File

@@ -2,16 +2,15 @@ package com.sdm.data.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.github.pagehelper.PageInfo;
import com.sdm.common.common.SdmResponse;
import com.sdm.common.common.ThreadLocalContext;
import com.sdm.common.entity.enums.DataTypeEnum;
import com.sdm.common.entity.enums.DirTypeEnum;
import com.sdm.common.entity.enums.NodeTypeEnum;
import com.sdm.common.entity.req.data.CreateDirReq;
import com.sdm.common.entity.req.data.DelDirReq;
import com.sdm.common.entity.req.data.DelFileReq;
import com.sdm.common.entity.req.data.UploadFilesReq;
import com.sdm.common.entity.req.data.*;
import com.sdm.common.entity.req.project.DelNodeReq;
import com.sdm.common.entity.req.project.GetAllNodeByNodeTypeReq;
import com.sdm.common.entity.req.project.GetTaskDetailReq;
@@ -300,15 +299,16 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
if (CollectionUtils.isNotEmpty(nextLevelUuids)) {
uuids.addAll(nextLevelUuids);
}
// 3、获取当前节点下的任务仅展示“应挂载在当前层”的任务避免任务提前出现在上层
List<List<String>> displayTagLevels = buildDisplayTagLevels(dimensionNodeTypeLevels);
List<String> taskUuids = getTaskByTagReq(req.getTagReq(), displayTagLevels, currentLevelIndex);
uuids.addAll(taskUuids);
log.info("获取节点下task的uudis:{}", taskUuids);
}
// 3、获取当前节点下的任务、算列
SdmResponse<List<AllNodeByProjectIdAndTypeResp>> nodeTaskList = simuluationNodeFeignClient.getNodeTaskList(chooseUuids);
if (nodeTaskList.isSuccess()) {
uuids.addAll(nodeTaskList.getData().stream().map(AllNodeByProjectIdAndTypeResp::getUuid).toList());
log.info("获取节点下task的uudis:{}", uuids);
}
// 4、获取任务下的算列
SdmResponse<List<AllNodeByProjectIdAndTypeResp>> taskRunList = simuluationNodeFeignClient.getTaskRunList(chooseUuids);
if (taskRunList.isSuccess()) {
uuids.addAll(taskRunList.getData().stream().map(AllNodeByProjectIdAndTypeResp::getUuid).toList());
@@ -336,6 +336,149 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
return SdmResponse.success(mergedResult);
}
private List<String> getTaskByTagReq(TagReq tagReq, List<List<String>> displayTagLevels, int currentLevelIndex) {
LambdaQueryChainWrapper<FileMetadataInfo> wrapper = new LambdaQueryChainWrapper<>(fileMetadataInfoService.getBaseMapper());
// 查task
wrapper.eq(FileMetadataInfo::getRelatedResourceUuidOwnType, NodeTypeEnum.TASK.getValue());
// tag1-tag10 可能是逗号拼接链,按完整 token 命中
if (ObjectUtils.isNotEmpty(tagReq)) {
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag1, tagReq.getTag1());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag2, tagReq.getTag2());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag3, tagReq.getTag3());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag4, tagReq.getTag4());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag5, tagReq.getTag5());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag6, tagReq.getTag6());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag7, tagReq.getTag7());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag8, tagReq.getTag8());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag9, tagReq.getTag9());
inByCurrentLevelCsv(wrapper, FileMetadataInfo::getTag10, tagReq.getTag10());
}
List<FileMetadataInfo> taskInfos = wrapper.list();
if (CollectionUtils.isEmpty(taskInfos)) {
return Collections.emptyList();
}
// 仅展示“应挂在当前展开层级”的任务:
// deepestMatchedLevel == currentLevelIndex 时才展示,避免任务提前出现在上层。
return taskInfos.stream()
.filter(task -> getDeepestMatchedLevel(task, displayTagLevels) == currentLevelIndex)
.sorted(Comparator
.comparing(FileMetadataInfo::getCreateTime, Comparator.nullsLast(LocalDateTime::compareTo)).reversed()
.thenComparing(FileMetadataInfo::getOriginalName, Comparator.nullsLast(String::compareTo))
.thenComparing(FileMetadataInfo::getId, Comparator.nullsLast(Long::compareTo)))
.map(FileMetadataInfo::getRelatedResourceUuid)
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
}
/**
* tag 字段可能存为 "a,b,c"。
* 只查询当前节点下的任务对于连续的节点类型机台1下又是机台2的展示机台1的任务只能挂机台1下机台2的任务只能挂机台2下展示
* 连续的机台一定会在数据总览中展开的所以不存在只有机台1没有机台2的情况这时候不需要考虑如果机台2不存在任务2需要挂在机台1下展示
* 1) column = v
* 3) column LIKE '%,v' (结尾)
*/
private <R> void inByCurrentLevelCsv(LambdaQueryChainWrapper<FileMetadataInfo> wrapper,
SFunction<FileMetadataInfo, R> column,
String csvValue) {
List<String> values = parseCsv(csvValue);
if (CollectionUtils.isEmpty(values)) {
return;
}
wrapper.and(q -> {
for (int i = 0; i < values.size(); i++) {
String value = values.get(i);
if (i > 0) {
q.or();
}
q.eq(column, value).or().likeLeft(column, "," + value);
}
});
}
private List<String> parseCsv(String value) {
if (StringUtils.isBlank(value)) {
return Collections.emptyList();
}
return Arrays.stream(value.split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
}
/**
* 将展示维度节点类型顺序映射为 tag 顺序tag1-tag2-tag4-tag3
* 一层个可能是展示多个tag (tag1-tag2+tag3-tag4)
*/
private List<List<String>> buildDisplayTagLevels(List<List<String>> dimensionNodeTypeLevels) {
if (CollectionUtils.isEmpty(dimensionNodeTypeLevels)) {
return Collections.emptyList();
}
Map<String, String> nodeTypeToTagMap = tagMapService.getTagMapName();
List<List<String>> displayTagLevels = new ArrayList<>();
for (List<String> levelNodeTypes : dimensionNodeTypeLevels) {
if (CollectionUtils.isEmpty(levelNodeTypes)) {
continue;
}
List<String> levelTags = levelNodeTypes.stream()
.map(nodeTypeToTagMap::get)
.filter(StringUtils::isNotBlank)
.distinct()
.toList();
if (CollectionUtils.isNotEmpty(levelTags)) {
displayTagLevels.add(levelTags);
}
}
return displayTagLevels;
}
/**
* 计算任务在当前展示顺序下可命中的最深层级。
* 命中规则从上往下逐层判断该层任一tag命中即可继续首次不命中即停止。
* 返回:最后命中层级索引;无命中返回 -1。
*/
private int getDeepestMatchedLevel(FileMetadataInfo task, List<List<String>> displayTagLevels) {
if (task == null || CollectionUtils.isEmpty(displayTagLevels)) {
return -1;
}
int deepestLevel = -1;
for (int level = 0; level < displayTagLevels.size(); level++) {
List<String> levelTags = displayTagLevels.get(level);
boolean levelMatched = CollectionUtils.isNotEmpty(levelTags) && levelTags.stream().anyMatch(tagKey ->
CollectionUtils.isNotEmpty(parseCsv(getTagValueByKey(task, tagKey)))
);
if (!levelMatched) {
break;
}
deepestLevel = level;
}
return deepestLevel;
}
private String getTagValueByKey(FileMetadataInfo task, String tagKey) {
if (task == null || StringUtils.isBlank(tagKey)) {
return null;
}
return switch (tagKey) {
case "tag1" -> task.getTag1();
case "tag2" -> task.getTag2();
case "tag3" -> task.getTag3();
case "tag4" -> task.getTag4();
case "tag5" -> task.getTag5();
case "tag6" -> task.getTag6();
case "tag7" -> task.getTag7();
case "tag8" -> task.getTag8();
case "tag9" -> task.getTag9();
case "tag10" -> task.getTag10();
default -> null;
};
}
/**
* 递归获取维度模板中指定节点的下一层级子节点UUID。
* <p>
@@ -776,6 +919,7 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
GetSimulationNodeTreeReq getSimulationNodeTreeReq = new GetSimulationNodeTreeReq();
getSimulationNodeTreeReq.setDimensionTemplateId(req.getDimensionTemplateId());
getSimulationNodeTreeReq.setFileIds(null);
getSimulationNodeTreeReq.setTagReq(req.getTagReq());
SdmResponse<List<FileMetadataChildrenDTO>> nodeDirInfos = getSimulationNodeTree(getSimulationNodeTreeReq);
List<Long> dirInfos = extractDirIdsFromResponse(nodeDirInfos);
@@ -790,6 +934,7 @@ public class DimensionTemplateServiceImpl extends ServiceImpl<DimensionTemplateM
GetSimulationNodeTreeReq getSimulationNodeTreeReq = new GetSimulationNodeTreeReq();
getSimulationNodeTreeReq.setDimensionTemplateId(req.getDimensionTemplateId());
getSimulationNodeTreeReq.setFileIds(req.getFileIds());
getSimulationNodeTreeReq.setTagReq(req.getTagReq());
SdmResponse<List<FileMetadataChildrenDTO>> nodeDirInfos = getSimulationNodeTree(getSimulationNodeTreeReq);
List<Long> dirInfos = extractDirIdsFromResponse(nodeDirInfos);