这个生成最终结构树的代码没有考虑到,如果是多资源的情况,即当matchAll为true时。表示全部资源。为false表示首个资源。比如说现在的情况是有五个表,相当于结构树会有五层。每一层都存放对应表的数据,比如说机组层肯定是只有一个的,但是系统层可能会匹配到多个系统。就是逻辑树他第二层系统层假如有一个节点,名称为燃煤系统。然后我们匹配资源的时候发现有两个1号燃煤系统和2号燃煤系统。这个时候最终的结构树的系统层就应该有两个节点来表示这两个系统。因此判断条件也需要改一下,从原来的只使用名称来模糊查询还需要使用到id。比如说系统匹配资源,就使用逻辑树的系统名称加上机组id。然后其子节点中也需要加入id(因为现在是没有加入的),最后如果是全部资源,那么这两个系统都要加入,如果是首个,就只需要加一个。 public ActionResult getInstantiateTemp(@RequestBody BizAssetStructureTreePagination pagination) throws Exception {
try {
// 参数校验
if (pagination.getUnitId() == null || pagination.getIsAuto() == null || pagination.getMatchRule() == null) {
return ActionResult.fail(MsgCode.VS009.get());
}
// 1. 获取逻辑树结构
List<AssetStructureTreeNode> logicTree = bizAssetStructureTreeService.getOneTreeStructure("0", 1);
if (logicTree == null || logicTree.isEmpty()) {
return ActionResult.fail(MsgCode.MSERR122.get());
}
List<AssetStructureTreeNode> builtTree = TreeBuilder.buildTree(logicTree);
TreeBuilder.setLevels(builtTree, 1);
// 2. 自动关联资源处理
if ("0".equals(pagination.getIsAuto())) {
boolean matchAll = "0".equals(pagination.getMatchRule());
builtTree = bizAssetStructureTreeService.getAutoResources(
builtTree,
matchAll,
(Integer) pagination.getUnitId()
);
}
// 返回结果
PageListVO vo = new PageListVO();
vo.setList(builtTree);
PaginationVO page = JsonUtil.getJsonToBean(pagination, PaginationVO.class);
vo.setPagination(page);
return ActionResult.success(vo);
} catch (Exception e) {
log.error("生成实例化树模版失败", e);
return ActionResult.fail(MsgCode.FA001.get());
}
}/**
* 生成完整的模版树
*
* @param matchAll 资源匹配规则,全部还是默认
* @return 树形结构列表
*/
@Override
public List<AssetStructureTreeNode> getAutoResources(List<AssetStructureTreeNode> logicTree, boolean matchAll, Integer unitId) {
// 1. 通过机组ID查询所有相关资源 (五类资源)
Map<AssetType, Map<Integer, Object>> allResources = fetchAllResourcesByUnit(unitId);
// 2. 查询已绑定的资源ID和类型
Map<AssetType, Set<Integer>> boundResources = getBoundResourcesWithType();
// 3. 筛选未绑定的资源
Map<AssetType, Map<Integer, Object>> availableResources = filterAvailableResources(allResources, boundResources);
// 4. 生成最终结构树
return generateFinalTree(logicTree, availableResources, matchAll);
}
// 第一步:获取机组关联的所有资源
private Map<AssetType, Map<Integer, Object>> fetchAllResourcesByUnit(Integer unitId) {
Map<AssetType, Map<Integer, Object>> resources = new EnumMap<>(AssetType.class);
// 1. 获取当前机组
BizBaseUnitEntity unit = unitService.getById(unitId);
if (unit != null) {
Map<Integer, Object> unitMap = new HashMap<>();
unitMap.put(unit.getId(), unit);
resources.put(AssetType.UNIT, unitMap);
}
// 2. 获取机组下的系统
LambdaQueryWrapper<BizBaseSystemEntity> sysWrapper = new LambdaQueryWrapper<>();
sysWrapper.eq(BizBaseSystemEntity::getUnitId, unitId)
.isNull(BizBaseSystemEntity::getDeletedAt);
Map<Integer, Object> systems = systemService.list(sysWrapper).stream()
.collect(Collectors.toMap(BizBaseSystemEntity::getId, Function.identity()));
resources.put(AssetType.SYSTEM, systems);
// 3. 获取系统下的设备
Set<Integer> sysIds = systems.keySet();
LambdaQueryWrapper<BizBaseDeviceEntity> deviceWrapper = new LambdaQueryWrapper<>();
deviceWrapper.in(!sysIds.isEmpty(), BizBaseDeviceEntity::getSysId, sysIds)
.isNull(BizBaseDeviceEntity::getDeletedAt);
Map<Integer, Object> devices = deviceService.list(deviceWrapper).stream()
.collect(Collectors.toMap(BizBaseDeviceEntity::getId, Function.identity()));
resources.put(AssetType.DEVICE, devices);
// 4. 获取设备下的检修单元
Set<Integer> deviceIds = devices.keySet();
LambdaQueryWrapper<BizBaseRepaUnitEntity> repaWrapper = new LambdaQueryWrapper<>();
repaWrapper.in(!deviceIds.isEmpty(), BizBaseRepaUnitEntity::getDeviceId, deviceIds)
.isNull(BizBaseRepaUnitEntity::getDeletedAt);
Map<Integer, Object> repaUnits = repaUnitService.list(repaWrapper).stream()
.collect(Collectors.toMap(BizBaseRepaUnitEntity::getId, Function.identity()));
resources.put(AssetType.REPA_UNIT, repaUnits);
// 5. 获取检修单元下的部件
Set<Integer> repaUnitIds = repaUnits.keySet();
LambdaQueryWrapper<BizBasePartsEntity> partsWrapper = new LambdaQueryWrapper<>();
partsWrapper.in(!repaUnitIds.isEmpty(), BizBasePartsEntity::getMaintUnitId, repaUnitIds)
.isNull(BizBasePartsEntity::getDeletedAt);
Map<Integer, Object> parts = partsService.list(partsWrapper).stream()
.collect(Collectors.toMap(BizBasePartsEntity::getId, Function.identity()));
resources.put(AssetType.PARTS, parts);
return resources;
}
// 第二步:获取已绑定的资源(带类型信息)
private Map<AssetType, Set<Integer>> getBoundResourcesWithType() {
MPJLambdaWrapper<BizAssetStructureTreeEntity> wrapper = new MPJLambdaWrapper<>();
// 基础查询条件
wrapper.select(BizAssetStructureTreeEntity::getAssetId)
.select(DictionaryDataEntity::getFullName)
.isNotNull(BizAssetStructureTreeEntity::getAssetId)
.isNull(BizAssetStructureTreeEntity::getDeletedAt);
// 关联字典表
wrapper.leftJoin(DictionaryDataEntity.class,
DictionaryDataEntity::getF_id,
BizAssetStructureTreeEntity::getTypeId);
// 执行查询
List<Map<String, Object>> boundList = baseMapper.selectJoinMaps(wrapper);
// 按资源类型分组
Map<AssetType, Set<Integer>> boundResources = new EnumMap<>(AssetType.class);
for (Map<String, Object> item : boundList) {
String typeName = (String) item.get("fullName");
Integer assetId = (Integer) item.get("assetId");
try {
AssetType type = AssetType.fromName(typeName);
boundResources.computeIfAbsent(type, k -> new HashSet<>()).add(assetId);
} catch (IllegalArgumentException e) {
log.warn("未知的资源类型: "+ typeName);
}
}
return boundResources;
}
// 第三步:筛选可用资源(移除已绑定的)
private Map<AssetType, Map<Integer, Object>> filterAvailableResources(
Map<AssetType, Map<Integer, Object>> allResources,
Map<AssetType, Set<Integer>> boundResources) {
// 筛选后的资源
Map<AssetType, Map<Integer, Object>> available = new EnumMap<>(AssetType.class);
// 有五类资源,使用循环,每次处理一类资源
for (AssetType type : allResources.keySet()) {
Map<Integer, Object> typeResources = allResources.get(type);
// 通过k获取boundResources中的值,如果没值就设置默认值Collections.emptySet()(空的集合)
Set<Integer> boundIds = boundResources.getOrDefault(type, Collections.emptySet());
// 创建新map存储可用资源,
Map<Integer, Object> availableMap = new HashMap<>();
// 如果typeResources中的id值不在boundIds中,就表示这个资源未被绑定,可以使用
typeResources.forEach((id, resource) -> {
if (!boundIds.contains(id)) {
availableMap.put(id, resource);
}
});
available.put(type, availableMap);
}
return available;
}
// 第四步:生成最终结构树
private List<AssetStructureTreeNode> generateFinalTree(
List<AssetStructureTreeNode> logicTree,
Map<AssetType, Map<Integer, Object>> availableResources,
boolean matchAll) {
List<AssetStructureTreeNode> resultTree = new ArrayList<>();
// 这里看似是循环,实际上,resultTree只会有一个值。
for (AssetStructureTreeNode node : logicTree) {
// 深度复制节点
AssetStructureTreeNode newNode = new AssetStructureTreeNode(node);
// 但是不用复制子节点
newNode.setChildren(new ArrayList<>());
// 处理资源绑定
processNodeResources(newNode, availableResources, matchAll);
// 递归处理子节点
if (!node.getChildren().isEmpty()) {
newNode.setChildren(generateFinalTree(node.getChildren(), availableResources, matchAll));
}
// 设置叶节点标志
newNode.setIsLeaf(newNode.getChildren().isEmpty());
resultTree.add(newNode);
}
return resultTree;
}
// 处理节点资源绑定
private void processNodeResources(
AssetStructureTreeNode node,
Map<AssetType, Map<Integer, Object>> availableResources,
boolean matchAll) {
try {
AssetType nodeType = AssetType.fromName(node.getTypeIdName());
// 跳过结构树节点
if (nodeType == AssetType.STRUCTURE_TREE) {
return;
}
// 获取该类型可用资源,比如说设备资源。key是设备枚举。v是map。所以使用nodeType,获取设备的全部资源。id为key,设备对象为v
Map<Integer, Object> resources = availableResources.get(nodeType);
if (resources == null || resources.isEmpty()) {
return;
}
// 根据节点名称匹配资源
List<Object> matchedResources = new ArrayList<>();
for (Object resource : resources.values()) {
// 获取资源名称,如果是设备就是设备表中设备名称
String resourceName = getResourceName(resource, nodeType);
// 如果资源名称包含节点名称,则添加
if (resourceName != null && resourceName.contains(node.getStructureName())) {
matchedResources.add(resource);
if (!matchAll && !matchedResources.isEmpty()) {
break; // 只匹配第一个
}
}
}
// 绑定匹配到的资源
if (!matchedResources.isEmpty()) {
Object firstResource = matchedResources.get(0);
bindResourceToNode(node, firstResource, nodeType);
}
} catch (IllegalArgumentException e) {
log.warn("未知的节点类型: "+ node.getTypeIdName());
}
}
// 获取资源名称
private String getResourceName(Object resource, AssetType type) {
switch (type) {
case UNIT:
return ((BizBaseUnitEntity) resource).getUnitName();
case SYSTEM:
return ((BizBaseSystemEntity) resource).getSysName();
case DEVICE:
return ((BizBaseDeviceEntity) resource).getDeviceName();
case REPA_UNIT:
return ((BizBaseRepaUnitEntity) resource).getRepaUnitName();
case PARTS:
return ((BizBasePartsEntity) resource).getPartsName();
default:
return null;
}
}
// 绑定资源到节点
private void bindResourceToNode(AssetStructureTreeNode node, Object resource, AssetType type) {
switch (type) {
case UNIT:
BizBaseUnitEntity unit = (BizBaseUnitEntity) resource;
node.setAssetId(unit.getId());
node.setAssetName(unit.getUnitName());
break;
case SYSTEM:
BizBaseSystemEntity system = (BizBaseSystemEntity) resource;
node.setAssetId(system.getId());
node.setAssetName(system.getSysName());
break;
case DEVICE:
BizBaseDeviceEntity device = (BizBaseDeviceEntity) resource;
node.setAssetId(device.getId());
node.setAssetName(device.getDeviceName());
node.setKks(device.getKks());
break;
case REPA_UNIT:
BizBaseRepaUnitEntity repaUnit = (BizBaseRepaUnitEntity) resource;
node.setAssetId(repaUnit.getId());
node.setAssetName(repaUnit.getRepaUnitName());
break;
case PARTS:
BizBasePartsEntity part = (BizBasePartsEntity) resource;
node.setAssetId(part.getId());
node.setAssetName(part.getPartsName());
break;
}
}