package com.estate.expert.admin.service.impl;
|
|
import com.estate.expert.admin.domain.standard.hierachy.Hierarchy;
|
import com.estate.expert.admin.domain.standard.hierachy.HierarchyData;
|
import com.estate.expert.admin.domain.standard.hierachy.HierarchyDto;
|
import com.estate.expert.admin.domain.standard.problem.Problem;
|
import com.estate.expert.admin.domain.standard.problem.ProblemRepository;
|
import com.estate.expert.admin.enums.BizResultCode;
|
import com.estate.expert.admin.service.HierarchyService;
|
import com.estate.expert.admin.service.common.CrudServiceBaseImpl;
|
import com.estate.expert.admin.utils.tree.TreeNode;
|
import com.estate.expert.admin.utils.tree.TreeRoot;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import javax.annotation.Resource;
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.TreeSet;
|
import java.util.UUID;
|
|
/**
|
* 层级管理服务实现
|
* 包括综合层级、设备体系
|
* 也包括部门数据
|
*/
|
@Service
|
public class HierarchyServiceImpl extends CrudServiceBaseImpl<Hierarchy, HierarchyDto> implements HierarchyService {
|
|
@Resource
|
private ProblemRepository problemRepository;
|
|
|
// @PostConstruct
|
// private void init(){
|
// load();
|
// }
|
//
|
// /*
|
// * 加载数据, 为了加速查询,将数据时刻保存在内存中
|
// * 层级数据不会频繁修改
|
// */
|
// private void load(){
|
// hierarchyRepository.findAll().forEach(store -> {
|
// store.buildTree();
|
// storeMap.put(store.getType(), store);
|
// });
|
// }
|
//
|
// private void save(Hierarchy store){
|
// store.setUpdateTime(LocalDateTime.now());
|
// hierarchyRepository.save(store);
|
// store.buildTree();
|
// storeMap.put(store.getType(), store);
|
// }
|
|
// @Override
|
// public void create(HierarchyType type, TreeNode<HierarchyData> root) {
|
// delete(type);
|
// Hierarchy store = new Hierarchy();
|
// store.setType(type);
|
// store.setContent(root);
|
// store.setCreateTime(LocalDateTime.now());
|
// save(store);
|
// }
|
//
|
// @Override
|
// public void delete(HierarchyType type) {
|
// var store = storeMap.get(type);
|
// if(store != null){
|
// hierarchyRepository.delete(store);
|
// storeMap.remove(type);
|
// }
|
// }
|
|
@Override
|
public TreeRoot<HierarchyData> root(Integer id) {
|
var store = get(id);
|
BizResultCode.HIERARCHY_NOT_FOUND.check(store == null);
|
return store.getContent();
|
}
|
|
@Override
|
public TreeNode<HierarchyData> node(Integer id, String path, boolean includeChildren) {
|
return root(id).get(path, includeChildren);
|
}
|
|
@Override
|
public List<TreeNode<HierarchyData>> children(Integer id, String path, String keyword) {
|
var children = root(id).children(path);
|
if(keyword == null || keyword.isEmpty()){
|
return children;
|
}
|
return children.stream().filter(node -> node.getName().contains(keyword)).toList();
|
}
|
|
@Override
|
public void edit(Integer id, String path, String name, HierarchyData data) {
|
var store = get(id);
|
BizResultCode.HIERARCHY_NOT_FOUND.check(store == null);
|
store.getContent().edit(path, name, data);
|
save(store);
|
}
|
|
@Override
|
public TreeNode<HierarchyData> addChild(Integer id, String parentPath, String name, HierarchyData data) {
|
var store = get(id);
|
BizResultCode.HIERARCHY_NOT_FOUND.check(store == null);
|
var child = store.getContent().addChild(parentPath, name, data);
|
save(store);
|
return child;
|
}
|
|
@Override
|
public void deleteNode(Integer id, String path) {
|
var store = get(id);
|
BizResultCode.HIERARCHY_NOT_FOUND.check(store == null);
|
store.getContent().remove(path);
|
save(store);
|
}
|
|
@Override
|
public void deleteNodes(Integer id, List<String> paths) {
|
var store = get(id);
|
BizResultCode.HIERARCHY_NOT_FOUND.check(store == null);
|
paths.forEach(store.getContent()::remove);
|
save(store);
|
}
|
|
@Override
|
public List<String> findAllPaths(Integer id, List<String> hierarchyPaths) {
|
// 如果没有传入路径,则返回所有路径
|
if(hierarchyPaths == null || hierarchyPaths.isEmpty()) {
|
var allPaths = root(id).root().allPaths();
|
var pathMap = new TreeSet<>(allPaths);
|
return pathMap.stream().toList();
|
}
|
return root(id).findAllPaths(hierarchyPaths);
|
}
|
|
@Override
|
@Transactional
|
public TreeNode<HierarchyData> cloneNode(Integer id, String sourcePath) {
|
var store = get(id);
|
BizResultCode.HIERARCHY_NOT_FOUND.check(store == null);
|
|
// 获取源节点
|
var sourceNode = store.getContent().get(sourcePath);
|
BizResultCode.HIERARCHY_NODE_NOT_FOUND.check(sourceNode == null);
|
|
// 获取父节点(复制到同一个父节点下)
|
var parent = sourceNode.getParent();
|
BizResultCode.HIERARCHY_PARENT_NOT_FOUND.check(parent == null);
|
|
// 生成新节点名称:原名称(克隆)
|
String newName = sourceNode.getName() + "(克隆)";
|
|
// 用于存储旧路径到新路径的映射
|
Map<String, String> pathMapping = new HashMap<>();
|
|
// 收集源节点树中所有节点的路径
|
List<String> sourceNodePaths = collectAllPaths(sourceNode);
|
|
// 克隆节点树到同一个父节点下
|
TreeNode<HierarchyData> newNode = cloneNodeRecursive(sourceNode, parent, newName);
|
|
// 重建树结构,更新所有路径
|
store.getContent().buildTree();
|
|
// 收集新节点树中所有节点的路径
|
List<String> newNodePaths = collectAllPaths(newNode);
|
|
// 建立路径映射关系(按照树的遍历顺序,源路径和新路径是一一对应的)
|
for (int i = 0; i < sourceNodePaths.size() && i < newNodePaths.size(); i++) {
|
pathMapping.put(sourceNodePaths.get(i), newNodePaths.get(i));
|
}
|
|
// 克隆关联的问题
|
cloneProblems(id, pathMapping);
|
|
// 保存
|
save(store);
|
|
return newNode;
|
}
|
|
/**
|
* 收集节点树中所有节点的路径(按照深度优先遍历顺序)
|
*/
|
private List<String> collectAllPaths(TreeNode<HierarchyData> node) {
|
List<String> paths = new ArrayList<>();
|
paths.add(node.getPath());
|
for (TreeNode<HierarchyData> child : node.getChildren().values()) {
|
paths.addAll(collectAllPaths(child));
|
}
|
return paths;
|
}
|
|
/**
|
* 递归克隆节点
|
*/
|
private TreeNode<HierarchyData> cloneNodeRecursive(TreeNode<HierarchyData> sourceNode,
|
TreeNode<HierarchyData> targetParent,
|
String newName) {
|
// 复制节点数据
|
HierarchyData newData = null;
|
if (sourceNode.getData() != null) {
|
newData = HierarchyData.builder()
|
.score(sourceNode.getData().getScore())
|
.weight(sourceNode.getData().getWeight())
|
.build();
|
}
|
|
// 创建新节点
|
TreeNode<HierarchyData> newNode = targetParent.addChild(newName, newData);
|
|
// 递归克隆所有子节点
|
for (TreeNode<HierarchyData> child : sourceNode.getChildren().values()) {
|
cloneNodeRecursive(child, newNode, child.getName());
|
}
|
|
return newNode;
|
}
|
|
/**
|
* 克隆关联的问题
|
*/
|
private void cloneProblems(Integer hierarchyId, Map<String, String> pathMapping) {
|
// 查询所有关联到源路径的问题
|
List<String> sourcePaths = pathMapping.keySet().stream().toList();
|
List<Problem> problems = problemRepository.findProblems(hierarchyId, sourcePaths);
|
|
if (problems.isEmpty()) {
|
return;
|
}
|
|
// 复制问题
|
List<Problem> newProblems = new ArrayList<>();
|
for (Problem problem : problems) {
|
// 使用 entityManager.detach 确保创建新实体
|
entityManager.detach(problem);
|
|
// 重置ID和名称
|
problem.setId(null);
|
problem.setName(UUID.randomUUID().toString());
|
|
// 更新 hierarchyPath 到新路径
|
String oldPath = problem.getHierarchyPath();
|
String newPath = pathMapping.get(oldPath);
|
if (newPath != null) {
|
problem.setHierarchyPath(newPath);
|
newProblems.add(problem);
|
}
|
}
|
|
// 批量保存新问题
|
if (!newProblems.isEmpty()) {
|
problemRepository.saveAll(newProblems);
|
}
|
}
|
|
}
|