fix:数据查询支持列头无关联,基于tag查询 查询

This commit is contained in:
2026-03-09 20:07:21 +08:00
parent d567ddb0b9
commit 30067719a3
3 changed files with 176 additions and 146 deletions

View File

@@ -61,22 +61,4 @@ public class GetSimulationTaskFileReq extends BaseReq {
@Schema(description = "标签筛选参数")
private TagReq tagReq;
@Schema(description = "项目级 dirId 列表")
private List<Long> projectDirIds;
@Schema(description = "阶段级 dirId 列表")
private List<Long> phaseDirIds;
@Schema(description = "机台级 dirId 列表")
private List<Long> machineDirIds;
@Schema(description = "工位级 dirId 列表")
private List<Long> workspaceDirIds;
@Schema(description = "任务级 dirId 列表")
private List<Long> taskDirIds;
@Schema(description = "算例级 dirId 列表")
private List<Long> runDirIDs;
}

View File

@@ -2,6 +2,8 @@ package com.sdm.data.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sdm.common.common.SdmResponse;
@@ -13,12 +15,11 @@ import com.sdm.common.entity.req.data.TagReq;
import com.sdm.common.entity.req.export.FileAnalysisExportExcelFormat;
import com.sdm.common.entity.req.export.FileAnalysisExportExcelParam;
import com.sdm.common.entity.resp.PageDataResp;
import com.sdm.common.utils.FileSizeUtils;
import com.sdm.common.utils.PageUtils;
import com.sdm.common.utils.SystemOperate;
import com.sdm.data.bo.ExportOperate;
import com.sdm.data.model.entity.FileMetadataInfo;
import com.sdm.data.model.entity.FileStorage;
import com.sdm.data.model.entity.FileTagRel;
import com.sdm.common.entity.req.data.GetSimulationTaskFileReq;
import com.sdm.data.model.req.QueryBigFileReq;
import com.sdm.common.entity.resp.data.SimulationTaskResultCurveResp;
@@ -48,9 +49,6 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
@Autowired
private IFileMetadataInfoService fileMetadataInfoService;
@Autowired
private DataStorageAnalysis dataStorageAnalysis;
@Autowired
private IMinioService MinIOService;
@@ -60,117 +58,194 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
@Autowired
private ExportOperate exportOperate;
@Autowired
private IFileTagRelService fileTagRelService;
@Override
public SdmResponse<PageDataResp<List<SimulationTaskResultCurveResp>>> getSimulationTaskFile(GetSimulationTaskFileReq getSimulationTaskFileReq) {
// 1. 构造查询条件
QueryBigFileReq queryBigFileReq = new QueryBigFileReq();
BeanUtils.copyProperties(getSimulationTaskFileReq, queryBigFileReq);
// 步骤 1: 收集所有直接传入的 dirId兼容旧参数
Set<Long> allDirIds = new HashSet<>();
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getProjectDirIds())) {
allDirIds.addAll(getSimulationTaskFileReq.getProjectDirIds());
}
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getPhaseDirIds())) {
allDirIds.addAll(getSimulationTaskFileReq.getPhaseDirIds());
}
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getMachineDirIds())) {
allDirIds.addAll(getSimulationTaskFileReq.getMachineDirIds());
}
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getWorkspaceDirIds())) {
allDirIds.addAll(getSimulationTaskFileReq.getWorkspaceDirIds());
}
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getTaskDirIds())) {
allDirIds.addAll(getSimulationTaskFileReq.getTaskDirIds());
}
if (CollectionUtils.isNotEmpty(getSimulationTaskFileReq.getRunDirIDs())) {
allDirIds.addAll(getSimulationTaskFileReq.getRunDirIDs());
}
// 步骤 2: 收集所有需要转换的 UUIDtagReq + 旧参数兼容)
Set<String> allUuids = new HashSet<>();
TagReq tagReq = getSimulationTaskFileReq.getTagReq();
if (ObjectUtils.isNotEmpty(tagReq)) {
collectTagUuids(allUuids, tagReq.getTag1(), tagReq.getTag2(), tagReq.getTag3(), tagReq.getTag4(), tagReq.getTag5(),
tagReq.getTag6(), tagReq.getTag7(), tagReq.getTag8(), tagReq.getTag9(), tagReq.getTag10(),
tagReq.getTaskId(), tagReq.getRunId());
}
// 步骤 3: 兼容处理旧的单个 uuid 和 dirId 字段uuid 优先
if (ObjectUtils.isNotEmpty(getSimulationTaskFileReq.getUuid())) {
allUuids.add(getSimulationTaskFileReq.getUuid());
FileMetadataInfo fileMetadataInfo = fileMetadataInfoService.lambdaQuery()
.eq(FileMetadataInfo::getRelatedResourceUuid, getSimulationTaskFileReq.getUuid())
.eq(FileMetadataInfo::getTenantId, ThreadLocalContext.getTenantId())
.one();
if (ObjectUtils.isNotEmpty(fileMetadataInfo)) {
queryBigFileReq.setDirId(fileMetadataInfo.getId());
} else {
log.error("未找到对应的 UUID 对应的目录");
public SdmResponse<PageDataResp<List<SimulationTaskResultCurveResp>>> getSimulationTaskFile(GetSimulationTaskFileReq req) {
// level=task 保留现有目录直查逻辑
if (NodeTypeEnum.TASK.getValue().equals(req.getLevel())) {
Long taskDirId = resolveTaskDirId(req);
if (ObjectUtils.isEmpty(taskDirId)) {
return PageUtils.getJsonObjectSdmResponse(new ArrayList<>(), new PageInfo<>());
}
} else if (ObjectUtils.isNotEmpty(getSimulationTaskFileReq.getDirId())) {
allDirIds.add(getSimulationTaskFileReq.getDirId());
QueryBigFileReq queryBigFileReq = new QueryBigFileReq();
queryBigFileReq.setDirId(taskDirId);
return getTaskLevelFile(req, queryBigFileReq);
}
// 步骤 4: 批量转换所有收集到的 UUID 并合并
if (CollectionUtils.isNotEmpty(allUuids)) {
List<Long> dirIdsFromUuids = fileMetadataInfoService.lambdaQuery()
.in(FileMetadataInfo::getRelatedResourceUuid, allUuids)
.eq(FileMetadataInfo::getTenantId, ThreadLocalContext.getTenantId())
.list().stream().map(FileMetadataInfo::getId).collect(Collectors.toList());
// 因为是交集查询如果传入了任何UUID但一个对应的目录都找不到那么最终结果必定为空。
// 直接返回空集可以避免无效的数据库查询。
if (CollectionUtils.isEmpty(dirIdsFromUuids)) {
log.warn("根据传入的 UUIDs 未找到任何对应的目录: {}", allUuids);
List<Long> fileIdsByDictTags = null;
if (CollectionUtils.isNotEmpty(req.getDictTags())) {
fileIdsByDictTags = extractFileIdsByTags(req);
if (CollectionUtils.isEmpty(fileIdsByDictTags)) {
return PageUtils.getJsonObjectSdmResponse(new ArrayList<>(), new PageInfo<>());
}
allDirIds.addAll(dirIdsFromUuids);
}
queryBigFileReq.setDirIds(allDirIds);
if (CollectionUtils.isNotEmpty(allDirIds)) {
queryBigFileReq.setDirIdsCount(allDirIds.size());
}
// 查询层级是task 只查task目录下的直系文件
if (NodeTypeEnum.TASK.getValue().equals(getSimulationTaskFileReq.getLevel())) {
return getTaskLevelFile(getSimulationTaskFileReq, queryBigFileReq);
PageHelper.startPage(req.getCurrent(), req.getSize());
var wrapper = fileMetadataInfoService.lambdaQuery()
.eq(FileMetadataInfo::getTenantId, ThreadLocalContext.getTenantId())
.isNull(FileMetadataInfo::getDeletedAt)
.eq(FileMetadataInfo::getIsLatest, true);
if (CollectionUtils.isNotEmpty(fileIdsByDictTags)) {
wrapper.in(FileMetadataInfo::getId, fileIdsByDictTags);
}
// 2. 调用大文件查询服务
SdmResponse<PageDataResp<List<FileStorage>>> searchResult = dataStorageAnalysis.listBigFile(queryBigFileReq);
PageDataResp<List<FileStorage>> pageDataResp = searchResult.getData();
List<FileStorage> fileStorages = pageDataResp.getData();
// 如果数据为空,提前返回
if (CollectionUtils.isEmpty(fileStorages)) {
return PageUtils.getJsonObjectSdmResponse(new ArrayList<>(), new PageInfo<>());
if (StringUtils.isNotBlank(req.getFileName())) {
wrapper.like(FileMetadataInfo::getOriginalName, req.getFileName());
}
if (CollectionUtils.isNotEmpty(req.getUploadUserId())) {
wrapper.in(FileMetadataInfo::getCreatorId, req.getUploadUserId());
}
if (ObjectUtils.isNotEmpty(req.getStartTime())) {
wrapper.ge(FileMetadataInfo::getCreateTime, req.getStartTime());
}
if (ObjectUtils.isNotEmpty(req.getEndTime())) {
wrapper.le(FileMetadataInfo::getCreateTime, req.getEndTime());
}
// 3. 一站式处理:获取文件元数据、构建父目录缓存、转换为响应对象并设置层级信息
List<Long> fileIdList = fileStorages.stream().map(FileStorage::getFileId).toList();
List<SimulationTaskResultCurveResp> finalResultList = hierarchyHelper.processFileHierarchy(
fileIdList,
SimulationTaskResultCurveResp.class,
(resp, folder, ownType) -> {
}
);
// 所属项目、阶段、机台、工位、任务、算列
applyTagFilters(wrapper, req.getTagReq());
setTagReqForSimulationResult(finalResultList, fileIdList);
List<FileMetadataInfo> fileMetadataInfos = wrapper.orderByDesc(FileMetadataInfo::getCreateTime).list();
PageInfo<FileMetadataInfo> page = new PageInfo<>(fileMetadataInfos);
// 4. 构造分页信息并返回
PageInfo<FileMetadataInfo> pageInfo = new PageInfo<>();
pageInfo.setTotal(pageDataResp.getTotal());
pageInfo.setPageNum(pageDataResp.getCurrentPage());
pageInfo.setPageSize(pageDataResp.getPageSize());
List<SimulationTaskResultCurveResp> finalResultList = fileMetadataInfos.stream().map(file -> {
SimulationTaskResultCurveResp resp = new SimulationTaskResultCurveResp();
BeanUtils.copyProperties(file, resp);
hierarchyHelper.setTagReqFromFileMetadata(file, resp);
return resp;
}).toList();
PageInfo<SimulationTaskResultCurveResp> pageInfo = new PageInfo<>(finalResultList);
pageInfo.setTotal(page.getTotal());
pageInfo.setPageNum(page.getPageNum());
pageInfo.setPageSize(page.getPageSize());
return PageUtils.getJsonObjectSdmResponse(finalResultList, pageInfo);
}
/**
* 复用listBigFile的逻辑在目录范围内根据dictTags筛出文件ID
*/
private List<Long> extractFileIdsByTags(GetSimulationTaskFileReq req) {
Map<String, Map<String, Integer>> dictIdMap = req.getDictTagIdsCache();
if (ObjectUtils.isEmpty(dictIdMap)) {
log.warn("Dict tags cache is empty, cannot extract file ids by tags");
return null;
}
Set<Integer> tagIds = new HashSet<>();
for (Map<String, Integer> valueMap : dictIdMap.values()) {
tagIds.addAll(valueMap.values());
}
if (CollectionUtils.isEmpty(tagIds)) {
return null;
}
return fileTagRelService.lambdaQuery()
.eq(FileTagRel::getTenantId, ThreadLocalContext.getTenantId())
.in(FileTagRel::getTagId, tagIds)
.select(FileTagRel::getFileId)
.list()
.stream()
.map(FileTagRel::getFileId)
.distinct()
.toList();
}
private void applyTagFilters(LambdaQueryChainWrapper<FileMetadataInfo> wrapper, TagReq tagReq) {
if (ObjectUtils.isEmpty(tagReq)) {
return;
}
// tag1-tag10 可能是逗号拼接链,按“最后一个值是当前层级值”过滤
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());
// task/run 按普通IN过滤
inByCsv(wrapper, FileMetadataInfo::getTaskId, tagReq.getTaskId());
inByCsv(wrapper, FileMetadataInfo::getRunId, tagReq.getRunId());
}
/**
* 同列多选IN用于普通单值字段taskId/runId
*/
private <R> void inByCsv(LambdaQueryChainWrapper<FileMetadataInfo> wrapper,
SFunction<FileMetadataInfo, R> column,
String csvValue) {
List<String> values = parseCsv(csvValue);
if (CollectionUtils.isNotEmpty(values)) {
wrapper.in(column, values);
}
}
/**
* tag字段可能存为 "a,b,c",当前层级值是最后一个 c
* 过滤条件column = v OR 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.and(one -> one.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();
}
private Long resolveTaskDirId(GetSimulationTaskFileReq req) {
if (ObjectUtils.isNotEmpty(req.getDirId())) {
return req.getDirId();
}
TagReq tagReq = req.getTagReq();
if (ObjectUtils.isNotEmpty(tagReq) && StringUtils.isNotBlank(tagReq.getTaskId())) {
List<String> taskIds = parseCsv(tagReq.getTaskId());
String targetTaskId = CollectionUtils.isNotEmpty(taskIds) ? taskIds.get(taskIds.size() - 1) : null;
if (StringUtils.isNotBlank(targetTaskId)) {
FileMetadataInfo fileMetadataInfo = fileMetadataInfoService.lambdaQuery()
.eq(FileMetadataInfo::getTenantId, ThreadLocalContext.getTenantId())
.eq(FileMetadataInfo::getRelatedResourceUuid, targetTaskId)
.isNull(FileMetadataInfo::getDeletedAt)
.one();
if (ObjectUtils.isNotEmpty(fileMetadataInfo)) {
return fileMetadataInfo.getId();
}
}
}
return null;
}
private void setTagReqForSimulationResult(List<SimulationTaskResultCurveResp> resultList, List<Long> fileIdList) {
if (CollectionUtils.isEmpty(resultList) || CollectionUtils.isEmpty(fileIdList)) {
return;
@@ -196,25 +271,6 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
}
}
private void collectTagUuids(Set<String> allUuids, String... values) {
if (ObjectUtils.isEmpty(values)) {
return;
}
for (String value : values) {
parseUuidChain(value).forEach(allUuids::add);
}
}
private List<String> parseUuidChain(String uuidChain) {
if (StringUtils.isBlank(uuidChain)) {
return Collections.emptyList();
}
return Arrays.stream(uuidChain.split(","))
.map(String::trim)
.filter(StringUtils::isNotBlank)
.toList();
}
private SdmResponse<PageDataResp<List<SimulationTaskResultCurveResp>>> getTaskLevelFile(GetSimulationTaskFileReq req, QueryBigFileReq queryBigFileReq) {
// level=task查task下的交付物文件夹 再根据fileType查具体的云图文件、曲线文件夹下的文件
List<FileMetadataInfo> deliverableFileInfoList = fileMetadataInfoService.lambdaQuery()

View File

@@ -360,8 +360,11 @@ public class FileMetadataHierarchyHelper {
for (int i = 1; i <= 10; i++) {
String tagValue = tagValues.get(i - 1);
String currentUuid = getLastUuid(tagValue);
String tagName = uuidNameMap.get(currentUuid);
List<String> uuidChain = parseUuidChain(tagValue);
String tagName = uuidChain.stream()
.map(uuidNameMap::get)
.filter(StringUtils::isNotBlank)
.collect(Collectors.joining("-"));
tagReqClass.getMethod("setTag" + i + "Name", String.class).invoke(tagReq, tagName);
}
tagReqClass.getMethod("setTaskName", String.class).invoke(tagReq, uuidNameMap.get(taskId));
@@ -386,15 +389,4 @@ public class FileMetadataHierarchyHelper {
.toList();
}
/**
* 获取逗号拼接uuid链中的最后一个uuid当前节点
*/
private String getLastUuid(String uuidChain) {
List<String> uuids = parseUuidChain(uuidChain);
if (CollectionUtils.isEmpty(uuids)) {
return null;
}
return uuids.get(uuids.size() - 1);
}
}