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 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 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 root(Integer id) { var store = get(id); BizResultCode.HIERARCHY_NOT_FOUND.check(store == null); return store.getContent(); } @Override public TreeNode node(Integer id, String path, boolean includeChildren) { return root(id).get(path, includeChildren); } @Override public List> 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 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 paths) { var store = get(id); BizResultCode.HIERARCHY_NOT_FOUND.check(store == null); paths.forEach(store.getContent()::remove); save(store); } @Override public List findAllPaths(Integer id, List 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 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 pathMapping = new HashMap<>(); // 收集源节点树中所有节点的路径 List sourceNodePaths = collectAllPaths(sourceNode); // 克隆节点树到同一个父节点下 TreeNode newNode = cloneNodeRecursive(sourceNode, parent, newName); // 重建树结构,更新所有路径 store.getContent().buildTree(); // 收集新节点树中所有节点的路径 List 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 collectAllPaths(TreeNode node) { List paths = new ArrayList<>(); paths.add(node.getPath()); for (TreeNode child : node.getChildren().values()) { paths.addAll(collectAllPaths(child)); } return paths; } /** * 递归克隆节点 */ private TreeNode cloneNodeRecursive(TreeNode sourceNode, TreeNode targetParent, String newName) { // 复制节点数据 HierarchyData newData = null; if (sourceNode.getData() != null) { newData = HierarchyData.builder() .score(sourceNode.getData().getScore()) .weight(sourceNode.getData().getWeight()) .build(); } // 创建新节点 TreeNode newNode = targetParent.addChild(newName, newData); // 递归克隆所有子节点 for (TreeNode child : sourceNode.getChildren().values()) { cloneNodeRecursive(child, newNode, child.getName()); } return newNode; } /** * 克隆关联的问题 */ private void cloneProblems(Integer hierarchyId, Map pathMapping) { // 查询所有关联到源路径的问题 List sourcePaths = pathMapping.keySet().stream().toList(); List problems = problemRepository.findProblems(hierarchyId, sourcePaths); if (problems.isEmpty()) { return; } // 复制问题 List 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); } } }