Merge branch 'main' of http://192.168.65.198:3000/toolchaintechnologycenter/spdm-backend
This commit is contained in:
@@ -8,8 +8,8 @@ import lombok.Getter;
|
||||
* 固定配置文件元数据响应中需要填充的字典标签字段映射关系
|
||||
*
|
||||
* 映射关系:
|
||||
* - disciplineTypeDictClass/disciplineDictValue → DISCIPLINE_TYPE
|
||||
* - fileTypeDictClass/fileTypeDictValue → ALL_FILE_TYPE
|
||||
* - disciplineTypeDictClass/disciplineDictValue/disciplineDictName → DISCIPLINE_TYPE
|
||||
* - fileTypeDictClass/fileTypeDictValue/fileTypeDictName → ALL_FILE_TYPE
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@@ -20,14 +20,14 @@ public enum FileDictTagEnum {
|
||||
* 字段: disciplineTypeDictClass, disciplineDictValue
|
||||
* dictClass: DISCIPLINE_TYPE
|
||||
*/
|
||||
DISCIPLINE_TYPE("DISCIPLINE_TYPE", "disciplineTypeDictClass", "disciplineDictValue"),
|
||||
DISCIPLINE_TYPE("DISCIPLINE_TYPE", "disciplineTypeDictClass", "disciplineDictValue", "disciplineDictName"),
|
||||
|
||||
/**
|
||||
* 文件类型标签
|
||||
* 字段: fileTypeDictClass, fileTypeDictValue
|
||||
* dictClass: ALL_FILE_TYPE
|
||||
*/
|
||||
FILE_TYPE("ALL_FILE_TYPE", "fileTypeDictClass", "fileTypeDictValue");
|
||||
FILE_TYPE("ALL_FILE_TYPE", "fileTypeDictClass", "fileTypeDictValue", "fileTypeDictName");
|
||||
|
||||
/**
|
||||
* 字典分类(对应数据库中的 dictClass)
|
||||
@@ -43,6 +43,11 @@ public enum FileDictTagEnum {
|
||||
* dictValue 字段名(完整字段名,如 disciplineDictValue)
|
||||
*/
|
||||
private final String dictValueFieldName;
|
||||
|
||||
/**
|
||||
* dictName 字段名(完整字段名,如 disciplineDictName)
|
||||
*/
|
||||
private final String dictNameFieldName;
|
||||
|
||||
/**
|
||||
* 根据 dictClass 获取对应的枚举
|
||||
|
||||
@@ -56,4 +56,26 @@ public class BaseResp {
|
||||
@Schema(description= "文件业务类型(1:模型文件 2:仿真报告、3:计算文件、4:曲线文件、5:云图文件,6:网格文件,7:计算过程文件)")
|
||||
@TableField("fileType")
|
||||
private Integer fileType;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 很重要,用于设置标签
|
||||
@Schema(description = "文件类型字典类")
|
||||
private String fileTypeDictClass;
|
||||
|
||||
@Schema(description = "文件类型字典值")
|
||||
private String fileTypeDictValue;
|
||||
|
||||
@Schema(description = "文件类型字典名称")
|
||||
private String fileTypeDictName;
|
||||
|
||||
@Schema(description = "学科类型字典类")
|
||||
private String disciplineTypeDictClass;
|
||||
|
||||
@Schema(description = "学科类型字典值")
|
||||
private String disciplineDictValue;
|
||||
|
||||
@Schema(description = "学科类型字典名称")
|
||||
private String disciplineDictName;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
}
|
||||
|
||||
@@ -63,21 +63,6 @@ public class FileMetadataInfoResp extends BaseResp implements Serializable {
|
||||
@Schema(description= "文件业务类型(1:模型文件 2:仿真报告、3:计算文件、4:曲线文件、5:云图文件,6:网格文件,7:计算过程文件)")
|
||||
private Integer fileType;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 很重要,用于设置标签
|
||||
@Schema(description = "文件类型字典类")
|
||||
private String fileTypeDictClass;
|
||||
@Schema(description = "文件类型字典值")
|
||||
private String fileTypeDictValue;
|
||||
|
||||
@Schema(description = "学科类型字典类")
|
||||
private String disciplineTypeDictClass;
|
||||
|
||||
@Schema(description = "学科类型字典值")
|
||||
private String disciplineDictValue;
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
@Schema(description = "数据类型:1-文件,2-文件夹")
|
||||
private Integer dataType;
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.sdm.data.model.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 文件字典标签聚合结果(按 fileId 聚合)
|
||||
*/
|
||||
@Data
|
||||
@Schema(name = "FileDictTagsAggDTO", description = "文件字典标签聚合结果(按 fileId 聚合)")
|
||||
public class FileDictTagsAggDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "文件ID")
|
||||
private Long fileId;
|
||||
|
||||
@Schema(description = "文件类型字典类")
|
||||
private String fileTypeDictClass;
|
||||
|
||||
@Schema(description = "文件类型字典值(逗号分隔)")
|
||||
private String fileTypeDictValue;
|
||||
|
||||
@Schema(description = "文件类型字典名称(逗号分隔)")
|
||||
private String fileTypeDictName;
|
||||
|
||||
@Schema(description = "学科类型字典类")
|
||||
private String disciplineTypeDictClass;
|
||||
|
||||
@Schema(description = "学科类型字典值(逗号分隔)")
|
||||
private String disciplineDictValue;
|
||||
|
||||
@Schema(description = "学科类型字典名称(逗号分隔)")
|
||||
private String disciplineDictName;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.sdm.data.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 文件字典标签聚合查询服务
|
||||
* 输入 fileIds,返回每个文件对应的 dictClass/dictValue 聚合结果
|
||||
*/
|
||||
public interface IFileDictTagQueryService {
|
||||
|
||||
/**
|
||||
* 泛型方法:为包含标签字段的响应对象列表批量填充文件字典标签
|
||||
* 要求 T 至少包含如下字段的 getter/setter:
|
||||
* - getId()
|
||||
* - setFileTypeDictClass(String)
|
||||
* - setFileTypeDictValue(String)
|
||||
* - setDisciplineTypeDictClass(String)
|
||||
* - setDisciplineDictValue(String)
|
||||
*/
|
||||
<T> void fillFileTagsForRespList(List<T> respList, Function<T, Long> idGetter);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,7 @@ import com.sdm.data.model.entity.FileStorage;
|
||||
import com.sdm.common.entity.req.data.GetSimulationTaskFileReq;
|
||||
import com.sdm.data.model.req.QueryBigFileReq;
|
||||
import com.sdm.common.entity.resp.data.SimulationTaskResultCurveResp;
|
||||
import com.sdm.data.service.DataStorageAnalysis;
|
||||
import com.sdm.data.service.IDataAnalysisService;
|
||||
import com.sdm.data.service.IFileMetadataInfoService;
|
||||
import com.sdm.data.service.IMinioService;
|
||||
import com.sdm.data.service.*;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
@@ -60,6 +57,9 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
|
||||
@Autowired
|
||||
private ExportOperate exportOperate;
|
||||
|
||||
@Autowired
|
||||
IFileDictTagQueryService fileDictTagQueryService;
|
||||
|
||||
@Override
|
||||
public SdmResponse<PageDataResp<List<SimulationTaskResultCurveResp>>> getSimulationTaskFile(GetSimulationTaskFileReq getSimulationTaskFileReq) {
|
||||
// 1. 构造查询条件
|
||||
@@ -102,6 +102,8 @@ public class DataAnalysisServiceImpl implements IDataAnalysisService {
|
||||
FileMetadataHierarchyHelper::setFileHierarchy
|
||||
);
|
||||
|
||||
fileDictTagQueryService.fillFileTagsForRespList(finalResultList, SimulationTaskResultCurveResp::getId);
|
||||
|
||||
// 4. 构造分页信息并返回
|
||||
PageInfo<FileMetadataInfo> pageInfo = new PageInfo<>();
|
||||
pageInfo.setTotal(pageDataResp.getTotal());
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.sdm.data.model.req.QueryBigFileReq;
|
||||
import com.sdm.data.model.resp.FileStorageQuotaResp;
|
||||
import com.sdm.data.model.resp.ListBigFileResp;
|
||||
import com.sdm.data.service.*;
|
||||
import com.sdm.data.service.IFileDictTagQueryService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
@@ -77,6 +78,9 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
|
||||
@Autowired
|
||||
IFileTagRelService fileTagRelService;
|
||||
|
||||
@Autowired
|
||||
IFileDictTagQueryService fileDictTagQueryService;
|
||||
|
||||
/**
|
||||
* 根据节点类型获取存储空间占用(支持批量查询)
|
||||
*/
|
||||
@@ -442,6 +446,9 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
|
||||
FileMetadataHierarchyHelper::setFileHierarchy
|
||||
);
|
||||
|
||||
// 2.1 批量填充文件字典标签(文件类型、学科类型)
|
||||
fileDictTagQueryService.fillFileTagsForRespList(finalResultList, ListBigFileResp::getId);
|
||||
|
||||
// 3. 构造分页信息并返回
|
||||
PageInfo<FileMetadataInfo> pageInfo = new PageInfo<>();
|
||||
pageInfo.setTotal(pageDataResp.getTotal());
|
||||
@@ -451,6 +458,7 @@ public class DataStorageAnalysisImpl implements DataStorageAnalysis {
|
||||
return PageUtils.getJsonObjectSdmResponse(finalResultList, pageInfo);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SdmResponse<PageDataResp<List<FileStorage>>> listBigFile(QueryBigFileReq queryBigFileReq) {
|
||||
PageInfo<FileStorage> fileStorages = getFileStorages(queryBigFileReq);
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
package com.sdm.data.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.entity.bo.DataDictionary;
|
||||
import com.sdm.common.entity.enums.FileDictTagEnum;
|
||||
import com.sdm.common.entity.req.system.DictTagReq;
|
||||
import com.sdm.common.feign.inter.system.ISysConfigFeignClient;
|
||||
import com.sdm.data.model.dto.FileDictTagsAggDTO;
|
||||
import com.sdm.data.model.entity.FileTagRel;
|
||||
import com.sdm.data.service.IFileDictTagQueryService;
|
||||
import com.sdm.data.service.IFileTagRelService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 文件字典标签聚合查询服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class FileDictTagQueryServiceImpl implements IFileDictTagQueryService {
|
||||
|
||||
private final IFileTagRelService fileTagRelService;
|
||||
private final ISysConfigFeignClient sysConfigFeignClient;
|
||||
|
||||
private Map<Long, FileDictTagsAggDTO> queryByFileIds(List<Long> fileIds) {
|
||||
if (CollectionUtils.isEmpty(fileIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Long tenantId = ThreadLocalContext.getTenantId();
|
||||
|
||||
// 1) file_tag_rel: DISTINCT fileId, tagId(因冗余祖先目录导致重复)
|
||||
List<FileTagRel> fileTagRels = fileTagRelService.getBaseMapper().selectList(
|
||||
Wrappers.<FileTagRel>query()
|
||||
.select("DISTINCT fileId, tagId")
|
||||
.eq("tenantId", tenantId)
|
||||
.in("fileId", fileIds)
|
||||
);
|
||||
if (CollectionUtils.isEmpty(fileTagRels)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 2) 提取 tagId 并批量查字典
|
||||
List<Integer> tagIds = fileTagRels.stream()
|
||||
.map(FileTagRel::getTagId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (CollectionUtils.isEmpty(tagIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
DictTagReq.BatchDictQueryReq batchReq = new DictTagReq.BatchDictQueryReq();
|
||||
batchReq.setItems(tagIds.stream().map(tagId -> {
|
||||
DictTagReq req = new DictTagReq();
|
||||
req.setDictId(tagId);
|
||||
return req;
|
||||
}).collect(Collectors.toList()));
|
||||
|
||||
SdmResponse<List<DataDictionary>> response = sysConfigFeignClient.batchQueryDictionaries(batchReq);
|
||||
if (response == null || !response.isSuccess() || CollectionUtils.isEmpty(response.getData())) {
|
||||
log.warn("Batch query dictionaries failed or returned empty, fileIds: {}", fileIds);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<Integer, DataDictionary> tagIdToDictMap = response.getData().stream()
|
||||
.filter(d -> d != null && d.id != null)
|
||||
.collect(Collectors.toMap(
|
||||
d -> d.id,
|
||||
Function.identity(),
|
||||
(v1, v2) -> v1
|
||||
));
|
||||
|
||||
// 3) fileId -> (dictClass -> 聚合数据:Set<dictValue> + Set<dictName>)
|
||||
Map<Long, Map<String, DictAggData>> agg = new HashMap<>();
|
||||
for (FileTagRel rel : fileTagRels) {
|
||||
if (rel == null || rel.getFileId() == null || rel.getTagId() == null) {
|
||||
continue;
|
||||
}
|
||||
DataDictionary dict = tagIdToDictMap.get(rel.getTagId());
|
||||
if (dict == null || dict.dictClass == null || dict.dictValue == null) {
|
||||
continue;
|
||||
}
|
||||
if (!FileDictTagEnum.isConfigured(dict.dictClass)) {
|
||||
continue;
|
||||
}
|
||||
DictAggData data = agg
|
||||
.computeIfAbsent(rel.getFileId(), k -> new HashMap<>())
|
||||
.computeIfAbsent(dict.dictClass, k -> new DictAggData());
|
||||
data.getDictValues().add(dict.dictValue);
|
||||
if (dict.dictName != null) {
|
||||
data.getDictNames().add(dict.dictName);
|
||||
}
|
||||
}
|
||||
|
||||
if (agg.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
// 4) 转为 DTO(目前只输出枚举配置的两类字段)
|
||||
Map<Long, FileDictTagsAggDTO> result = new HashMap<>();
|
||||
for (Map.Entry<Long, Map<String, DictAggData>> e : agg.entrySet()) {
|
||||
Long fileId = e.getKey();
|
||||
Map<String, DictAggData> classMap = e.getValue();
|
||||
if (classMap == null || classMap.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FileDictTagsAggDTO dto = new FileDictTagsAggDTO();
|
||||
dto.setFileId(fileId);
|
||||
|
||||
for (Map.Entry<String, DictAggData> classEntry : classMap.entrySet()) {
|
||||
String dictClass = classEntry.getKey();
|
||||
DictAggData data = classEntry.getValue();
|
||||
if (data == null || data.getDictValues().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String dictValues = String.join(",", data.getDictValues());
|
||||
String dictNames = data.getDictNames().isEmpty()
|
||||
? null
|
||||
: String.join(",", data.getDictNames());
|
||||
FileDictTagEnum tagEnum = FileDictTagEnum.getByDictClass(dictClass);
|
||||
if (tagEnum == null) {
|
||||
continue;
|
||||
}
|
||||
if (tagEnum == FileDictTagEnum.FILE_TYPE) {
|
||||
dto.setFileTypeDictClass(tagEnum.getDictClass());
|
||||
dto.setFileTypeDictValue(dictValues);
|
||||
dto.setFileTypeDictName(dictNames);
|
||||
} else if (tagEnum == FileDictTagEnum.DISCIPLINE_TYPE) {
|
||||
dto.setDisciplineTypeDictClass(tagEnum.getDictClass());
|
||||
dto.setDisciplineDictValue(dictValues);
|
||||
dto.setDisciplineDictName(dictNames);
|
||||
}
|
||||
}
|
||||
result.put(fileId, dto);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void fillFileTagsForRespList(List<T> respList, Function<T, Long> idGetter) {
|
||||
if (CollectionUtils.isEmpty(respList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 收集文件ID
|
||||
List<Long> fileIds = respList.stream()
|
||||
.map(idGetter)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
if (CollectionUtils.isEmpty(fileIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询聚合标签
|
||||
Map<Long, FileDictTagsAggDTO> fileIdToTagsMap = queryByFileIds(fileIds);
|
||||
if (MapUtils.isEmpty(fileIdToTagsMap)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 通过反射,将标签字段填充到 Resp 对象中(基于 FileDictTagEnum 的配置)
|
||||
for (T resp : respList) {
|
||||
Long fileId = idGetter.apply(resp);
|
||||
if (fileId == null) {
|
||||
continue;
|
||||
}
|
||||
FileDictTagsAggDTO tags = fileIdToTagsMap.get(fileId);
|
||||
if (tags == null) {
|
||||
continue;
|
||||
}
|
||||
for (FileDictTagEnum tagEnum : FileDictTagEnum.values()) {
|
||||
String dictValues = getDictValuesByEnum(tags, tagEnum);
|
||||
String dictNames = getDictNamesByEnum(tags, tagEnum);
|
||||
if (dictValues == null && dictNames == null) {
|
||||
continue;
|
||||
}
|
||||
String dictClass = tagEnum.getDictClass();
|
||||
String dictClassFieldName = tagEnum.getDictClassFieldName();
|
||||
String dictValueFieldName = tagEnum.getDictValueFieldName();
|
||||
String dictNameFieldName = tagEnum.getDictNameFieldName();
|
||||
try {
|
||||
// setXxxDictClass
|
||||
String classSetterName = "set" + Character.toUpperCase(dictClassFieldName.charAt(0)) + dictClassFieldName.substring(1);
|
||||
resp.getClass().getMethod(classSetterName, String.class)
|
||||
.invoke(resp, dictClass);
|
||||
// setXxxDictValue
|
||||
if (dictValues != null) {
|
||||
String valueSetterName = "set" + Character.toUpperCase(dictValueFieldName.charAt(0)) + dictValueFieldName.substring(1);
|
||||
resp.getClass().getMethod(valueSetterName, String.class)
|
||||
.invoke(resp, dictValues);
|
||||
}
|
||||
// setXxxDictName(如果存在)
|
||||
if (dictNames != null) {
|
||||
String nameSetterName = "set" + Character.toUpperCase(dictNameFieldName.charAt(0)) + dictNameFieldName.substring(1);
|
||||
resp.getClass().getMethod(nameSetterName, String.class)
|
||||
.invoke(resp, dictNames);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("填充文件标签信息失败, fileId: {}, respClass: {}, dictClass: {}, error: {}",
|
||||
fileId, resp.getClass().getName(), dictClass, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举类型,从聚合结果中取出对应的字典值
|
||||
*/
|
||||
private String getDictValuesByEnum(FileDictTagsAggDTO tags, FileDictTagEnum tagEnum) {
|
||||
if (tags == null || tagEnum == null) {
|
||||
return null;
|
||||
}
|
||||
if (tagEnum == FileDictTagEnum.FILE_TYPE) {
|
||||
return tags.getFileTypeDictValue();
|
||||
} else if (tagEnum == FileDictTagEnum.DISCIPLINE_TYPE) {
|
||||
return tags.getDisciplineDictValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举类型,从聚合结果中取出对应的字典名称
|
||||
*/
|
||||
private String getDictNamesByEnum(FileDictTagsAggDTO tags, FileDictTagEnum tagEnum) {
|
||||
if (tags == null || tagEnum == null) {
|
||||
return null;
|
||||
}
|
||||
if (tagEnum == FileDictTagEnum.FILE_TYPE) {
|
||||
return tags.getFileTypeDictName();
|
||||
} else if (tagEnum == FileDictTagEnum.DISCIPLINE_TYPE) {
|
||||
return tags.getDisciplineDictName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部聚合数据结构:同时持有 dictValue 和 dictName 的去重集合
|
||||
*/
|
||||
private static class DictAggData {
|
||||
private final LinkedHashSet<String> dictValues = new LinkedHashSet<>();
|
||||
private final LinkedHashSet<String> dictNames = new LinkedHashSet<>();
|
||||
|
||||
public LinkedHashSet<String> getDictValues() {
|
||||
return dictValues;
|
||||
}
|
||||
|
||||
public LinkedHashSet<String> getDictNames() {
|
||||
return dictNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,12 @@ import com.google.common.collect.Sets;
|
||||
import com.sdm.common.common.SdmResponse;
|
||||
import com.sdm.common.common.ThreadLocalContext;
|
||||
import com.sdm.common.entity.ExportExcelFormat;
|
||||
import com.sdm.common.entity.bo.DataDictionary;
|
||||
import com.sdm.common.entity.constants.NumberConstants;
|
||||
import com.sdm.common.entity.constants.PermConstants;
|
||||
import com.sdm.common.entity.enums.*;
|
||||
import com.sdm.common.entity.pojo.task.TaskBaseInfo;
|
||||
import com.sdm.common.entity.req.data.*;
|
||||
import com.sdm.common.entity.req.project.SpdmNodeListReq;
|
||||
import com.sdm.common.entity.req.system.DictTagReq;
|
||||
import com.sdm.common.entity.req.system.LaunchApproveReq;
|
||||
import com.sdm.common.entity.req.system.UserListReq;
|
||||
import com.sdm.common.entity.req.system.UserQueryReq;
|
||||
@@ -28,7 +26,6 @@ import com.sdm.common.entity.resp.data.*;
|
||||
import com.sdm.common.entity.resp.project.SimulationNodeResp;
|
||||
import com.sdm.common.entity.resp.system.CIDUserResp;
|
||||
import com.sdm.common.feign.impl.project.SimulationNodeFeignClientImpl;
|
||||
import com.sdm.common.feign.impl.system.SysConfigFeignClientImpl;
|
||||
import com.sdm.common.feign.impl.system.SysUserFeignClientImpl;
|
||||
import com.sdm.common.feign.inter.project.ISimulationNodeFeignClient;
|
||||
import com.sdm.common.feign.inter.system.IApproveFeignClient;
|
||||
@@ -40,6 +37,7 @@ import com.sdm.common.utils.excel.ExcelUtil;
|
||||
import com.sdm.data.aop.PermissionCheckAspect;
|
||||
import com.sdm.data.model.bo.ApprovalFileDataContentsModel;
|
||||
import com.sdm.data.model.dto.ExportKnowledgeDto;
|
||||
import com.sdm.data.model.dto.FileDictTagsAggDTO;
|
||||
import com.sdm.data.model.entity.*;
|
||||
import com.sdm.data.model.enums.ApproveFileActionENUM;
|
||||
import com.sdm.data.model.req.*;
|
||||
@@ -137,6 +135,9 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
@Autowired
|
||||
private IFileTagRelService fileTagRelService;
|
||||
|
||||
@Autowired
|
||||
private IFileDictTagQueryService fileDictTagQueryService;
|
||||
|
||||
@Autowired
|
||||
ISimulationParameterLibraryCategoryObjectService paramObjectService;
|
||||
|
||||
@@ -805,6 +806,11 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
dto.setKnowledgeBaseName(extractRelativePath(fileMetadataInfoService.lambdaQuery().eq(FileMetadataInfo::getId, dto.getParentId()).one()));
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
// 批量填充文件标签信息(仅对文件类型生效)
|
||||
List<FileMetadataInfoResp> fileDtos = dtoList.stream()
|
||||
.filter(dto -> dto != null && dto.getDataType() != null && DataTypeEnum.FILE.getValue() == dto.getDataType())
|
||||
.toList();
|
||||
fileDictTagQueryService.fillFileTagsForRespList(fileDtos, FileMetadataInfoResp::getId);
|
||||
PageDataResp<List<FileStorage>> pageDataResp = searchResult.getData();
|
||||
PageInfo page = new PageInfo();
|
||||
page.setPageNum(pageDataResp.getCurrentPage());
|
||||
@@ -890,9 +896,12 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
dto.setKnowledgeBaseName(knowledgeBaseName);
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
// 批量填充文件标签信息
|
||||
fillFileTags(dtoList);
|
||||
|
||||
// 批量填充文件标签信息(仅对文件类型生效)
|
||||
List<FileMetadataInfoResp> fileDtos = dtoList.stream()
|
||||
.filter(dto -> dto != null && dto.getDataType() != null && DataTypeEnum.FILE.getValue() == dto.getDataType())
|
||||
.toList();
|
||||
fileDictTagQueryService.fillFileTagsForRespList(fileDtos, FileMetadataInfoResp::getId);
|
||||
PageInfo<FileMetadataInfoResp> page1 = new PageInfo<>(dtoList);
|
||||
page1.setTotal(total);
|
||||
return PageUtils.getJsonObjectSdmResponse(dtoList, page1);
|
||||
@@ -2115,186 +2124,6 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量填充文件标签信息到 FileMetadataInfoResp
|
||||
* 从 file_tag_rel 和 simulation_data_dictionary 查询标签,按 dictClass 分组
|
||||
* 格式:disciplineTypeDictClass: DISCIPLINE_TYPE, disciplineDictValue: '流体,机器人,动画'
|
||||
*
|
||||
* @param dtoList 文件元数据响应列表
|
||||
*/
|
||||
private void fillFileTags(List<FileMetadataInfoResp> dtoList) {
|
||||
if (CollectionUtils.isEmpty(dtoList)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Long tenantId = ThreadLocalContext.getTenantId();
|
||||
|
||||
// 1. 提取所有文件ID(只包含文件类型,排除目录)
|
||||
List<Long> fileIds = dtoList.stream()
|
||||
.filter(dto -> DataTypeEnum.FILE.getValue()==(dto.getDataType()))
|
||||
.map(FileMetadataInfoResp::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (CollectionUtils.isEmpty(fileIds)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 批量查询 file_tag_rel 获取文件对应的 tagId
|
||||
List<FileTagRel> fileTagRels = fileTagRelService.lambdaQuery()
|
||||
.eq(FileTagRel::getTenantId, tenantId)
|
||||
.in(FileTagRel::getFileId, fileIds)
|
||||
.select(FileTagRel::getFileId, FileTagRel::getTagId)
|
||||
.list();
|
||||
|
||||
if (CollectionUtils.isEmpty(fileTagRels)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 提取所有 tagId
|
||||
List<Integer> tagIds = fileTagRels.stream()
|
||||
.map(FileTagRel::getTagId)
|
||||
.distinct()
|
||||
.toList();
|
||||
|
||||
// 4. 批量查询 simulation_data_dictionary 获取标签详情
|
||||
List<DictTagReq> dictTagReqs = tagIds.stream()
|
||||
.map(tagId -> {
|
||||
DictTagReq req = new DictTagReq();
|
||||
req.setDictId(tagId);
|
||||
return req;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
DictTagReq.BatchDictQueryReq batchReq = new DictTagReq.BatchDictQueryReq();
|
||||
batchReq.setItems(dictTagReqs);
|
||||
SdmResponse<List<DataDictionary>> response = sysConfigFeignClient.batchQueryDictionaries(batchReq);
|
||||
|
||||
if (!response.isSuccess() || CollectionUtils.isEmpty(response.getData())) {
|
||||
log.warn("Batch query dictionaries failed or returned empty");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. 构建 tagId -> 字典信息的映射
|
||||
Map<Integer, DataDictionary> tagIdToDictMap = response.getData().stream()
|
||||
.filter(dict -> dict.id != null)
|
||||
.collect(Collectors.toMap(
|
||||
dict -> dict.id,
|
||||
dict -> dict,
|
||||
(v1, v2) -> v1
|
||||
));
|
||||
|
||||
// 6. 构建 fileId -> tagIds 的映射(tagId 去重)
|
||||
Map<Long, List<Integer>> fileToTagsMap = fileTagRels.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
FileTagRel::getFileId,
|
||||
Collectors.mapping(FileTagRel::getTagId, Collectors.toSet())
|
||||
))
|
||||
.entrySet().stream()
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
entry -> new ArrayList<>(entry.getValue())
|
||||
));
|
||||
|
||||
// 7. 为每个文件填充标签信息
|
||||
for (FileMetadataInfoResp dto : dtoList) {
|
||||
if (!(DataTypeEnum.FILE.getValue()==(dto.getDataType()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Integer> fileTags = fileToTagsMap.get(dto.getId());
|
||||
if (CollectionUtils.isEmpty(fileTags)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 按 dictClass 分组,聚合 dictValue(只处理配置的 dictClass)
|
||||
Map<String, List<String>> classToDictValuesMap = new HashMap<>();
|
||||
|
||||
for (Integer tagId : fileTags) {
|
||||
DataDictionary dictInfo = tagIdToDictMap.get(tagId);
|
||||
if (dictInfo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String dictClass = dictInfo.dictClass;
|
||||
String dictValue = dictInfo.dictValue;
|
||||
|
||||
// 只处理枚举中配置的 dictClass
|
||||
if (dictClass != null && dictValue != null && FileDictTagEnum.isConfigured(dictClass)) {
|
||||
classToDictValuesMap
|
||||
.computeIfAbsent(dictClass, k -> new ArrayList<>())
|
||||
.add(dictValue);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置到 DTO 中(使用枚举配置)
|
||||
for (Map.Entry<String, List<String>> entry : classToDictValuesMap.entrySet()) {
|
||||
String dictClass = entry.getKey();
|
||||
String dictValues = String.join(",", entry.getValue());
|
||||
|
||||
// 根据枚举配置设置对应的字段
|
||||
FileDictTagEnum tagEnum = FileDictTagEnum.getByDictClass(dictClass);
|
||||
if (tagEnum != null) {
|
||||
setDictTagFieldsByEnum(dto, tagEnum, dictValues);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举配置设置字典标签字段(推荐使用)
|
||||
* 直接使用枚举配置的完整字段名,无需拼接
|
||||
*
|
||||
* @param dto FileMetadataInfoResp 对象
|
||||
* @param tagEnum 字典标签枚举
|
||||
* @param dictValues 字典值(逗号分隔)
|
||||
*/
|
||||
private void setDictTagFieldsByEnum(FileMetadataInfoResp dto, FileDictTagEnum tagEnum, String dictValues) {
|
||||
if (tagEnum == null || dictValues == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String dictClass = tagEnum.getDictClass();
|
||||
String dictClassFieldName = tagEnum.getDictClassFieldName();
|
||||
String dictValueFieldName = tagEnum.getDictValueFieldName();
|
||||
|
||||
try {
|
||||
// 设置 dictClass 字段
|
||||
Field dictClassField = findField(FileMetadataInfoResp.class, dictClassFieldName);
|
||||
if (dictClassField != null) {
|
||||
dictClassField.setAccessible(true);
|
||||
dictClassField.set(dto, dictClass);
|
||||
} else {
|
||||
log.warn("Field '{}' not found in FileMetadataInfoResp, please add field for dictClass: {}",
|
||||
dictClassFieldName, dictClass);
|
||||
}
|
||||
|
||||
// 设置 dictValue 字段
|
||||
Field dictValueField = findField(FileMetadataInfoResp.class, dictValueFieldName);
|
||||
if (dictValueField != null) {
|
||||
dictValueField.setAccessible(true);
|
||||
dictValueField.set(dto, dictValues);
|
||||
} else {
|
||||
log.warn("Field '{}' not found in FileMetadataInfoResp, please add field for dictClass: {}",
|
||||
dictValueFieldName, dictClass);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to set dict tag fields for dictClass: {}, error: {}", dictClass, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在类及其父类中查找字段
|
||||
*/
|
||||
private Field findField(Class<?> clazz, String fieldName) {
|
||||
while (clazz != null && clazz != Object.class) {
|
||||
try {
|
||||
return clazz.getDeclaredField(fieldName);
|
||||
} catch (NoSuchFieldException e) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private void bindSimulationPool(UploadFilesReq req, FileMetadataInfo fileInfo) {
|
||||
@@ -2554,6 +2383,22 @@ public class MinioFileIDataFileServiceImpl implements IDataFileService {
|
||||
fileMetadataInfo.setUpdateTime(LocalDateTime.now());
|
||||
fileMetadataInfo.setUpdaterId(ThreadLocalContext.getUserId());
|
||||
fileMetadataInfo.setFileType(req.getFileType());
|
||||
|
||||
//绑定文件和工况库的关系
|
||||
if (CollectionUtils.isNotEmpty(req.getSimulationPoolInfoList())) {
|
||||
// 先删除原先所有的文件绑定关系
|
||||
fileSimulationMappingService.lambdaUpdate().eq(FileSimulationMapping::getFileId, fileMetadataInfo.getId()).remove();
|
||||
for (SimulationPoolInfo simulationPoolInfo : req.getSimulationPoolInfoList()) {
|
||||
for (String simulationPoolTaskId : simulationPoolInfo.getSimulationPoolTaskIds()) {
|
||||
FileSimulationMapping fileSimulationMapping = new FileSimulationMapping();
|
||||
fileSimulationMapping.setFileId(fileMetadataInfo.getId());
|
||||
fileSimulationMapping.setSimulationPoolId(simulationPoolInfo.getSimulationPoolId());
|
||||
fileSimulationMapping.setSimulationPoolVersion(simulationPoolInfo.getSimulationPoolVersion());
|
||||
fileSimulationMapping.setSimulationPoolTaskId(simulationPoolTaskId);
|
||||
fileSimulationMappingService.save(fileSimulationMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新标签(如果有)
|
||||
if (CollectionUtils.isNotEmpty(req.getDictTags())) {
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Map;
|
||||
*/
|
||||
@Configuration
|
||||
@PropertySource(
|
||||
value = "classpath:common-${spring.profiles.active:lyric}.yml",
|
||||
value = "classpath:common-${spring.profiles.active:}.yml",
|
||||
factory = CommonConfig.YamlPropertySourceFactory.class
|
||||
)
|
||||
public class CommonConfig {
|
||||
|
||||
@@ -21,7 +21,7 @@ public class DataSourcePreWarmer {
|
||||
@Qualifier("secondDataSource") DataSource secondDataSource) {
|
||||
return args -> {
|
||||
try (Connection conn = secondDataSource.getConnection()) {
|
||||
log.info("✅ secondDataSource 预热成功,连接已建立: {}", conn);
|
||||
log.info("✅ secondDataSource 预热成功,连接已建立: {}", conn.getMetaData().getURL());
|
||||
} catch (Exception e) {
|
||||
log.error("❌ secondDataSource 预热失败", e);
|
||||
throw new RuntimeException(e);
|
||||
@@ -29,6 +29,20 @@ public class DataSourcePreWarmer {
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApplicationRunner thirdDataSourcePreWarmer(
|
||||
@Qualifier("thirdDataSource") DataSource thirdDataSource) {
|
||||
return args -> {
|
||||
try (Connection conn = thirdDataSource.getConnection()) {
|
||||
log.info("✅ thirdDataSource 预热成功,连接已建立: {}", conn.getMetaData().getURL());
|
||||
} catch (Exception e) {
|
||||
log.error("❌ thirdDataSource 预热失败", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
// @Bean
|
||||
// public ApplicationRunner mainDataSourcePreWarmer(
|
||||
// @Qualifier("masterDataSource") DataSource master,
|
||||
|
||||
@@ -173,15 +173,15 @@ public class SimulationJob implements Serializable {
|
||||
@TableField("dirId")
|
||||
private Long dirId;
|
||||
|
||||
@Schema(description = "输入主文件正则")
|
||||
@Schema(description = "输入主文件正则,params里取的base64的字符串")
|
||||
@TableField("inputFormat")
|
||||
private String inputFormat;
|
||||
|
||||
@Schema(description = "输入从文件正则")
|
||||
@Schema(description = "输入从文件正则的base64的字符串")
|
||||
@TableField("slaveFormat")
|
||||
private String slaveFormat;
|
||||
|
||||
@Schema(description = "输出文件正则")
|
||||
@Schema(description = "输出文件正则的base64的字符串")
|
||||
@TableField("outputFormat")
|
||||
private String outputFormat;
|
||||
|
||||
|
||||
@@ -288,8 +288,6 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
|
||||
simulationJob.setRunName(req.getRunName());
|
||||
// 软件及文件关联
|
||||
simulationJob.setSoftwareId(req.getSoftwareId());
|
||||
// 下面的待定
|
||||
// simulationJob.setInputFileId(null);
|
||||
simulationJob.setJobId(jobId);
|
||||
// 没必要要
|
||||
// simulationJob.setJobDetailId("");
|
||||
@@ -325,6 +323,13 @@ public class PbsServiceDecorator implements IPbsServiceDecorator {
|
||||
simulationJob.setUpdateTime(LocalDateTime.now());
|
||||
// 当前节点minio的文件夹id
|
||||
simulationJob.setDirId(req.getDirId());
|
||||
|
||||
simulationJob.setInputFileId(req.getInputFileId());
|
||||
simulationJob.setInputFormat(req.getInputFormat());
|
||||
simulationJob.setSlaveFormat(req.getSlaveFormat());
|
||||
simulationJob.setOutputFormat(req.getOutputFormat());
|
||||
simulationJob.setProcessDefinitionId(req.getProcessDefinitionId());
|
||||
simulationJob.setProcessInstanceId(req.getProcessInstanceId());
|
||||
simulationJobService.save(simulationJob);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user