From 73360d70ceb332bd8ce215caf191e49dfa58e2d5 Mon Sep 17 00:00:00 2001 From: dk <1260500659@qq.com> Date: Thu, 7 May 2026 11:10:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E4=BA=A7=E5=93=81=E9=9C=80=E6=B1=82):=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=A7=E5=93=81=E9=9C=80=E6=B1=82=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=81=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E9=9C=80=E6=B1=82=E6=A0=91=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/ProductRequirementMapper.java | 18 ++- .../ProductRequirementServiceImpl.java | 128 +++++++++++++----- 2 files changed, 114 insertions(+), 32 deletions(-) diff --git a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/product/ProductRequirementMapper.java b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/product/ProductRequirementMapper.java index 5dab8f0..b5e8573 100644 --- a/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/product/ProductRequirementMapper.java +++ b/rdms-project/rdms-project-boot/src/main/java/com/njcn/rdms/module/project/dal/mysql/product/ProductRequirementMapper.java @@ -20,6 +20,22 @@ public interface ProductRequirementMapper extends BaseMapperX selectPage(ProductRequirementPageReqVO reqVO) { + LambdaQueryWrapperX queryWrapper = buildQueryWrapper(reqVO); + return selectPage(reqVO, queryWrapper); + } + + /** + * 查询所有符合条件的需求列表(不分页,用于树形查询) + */ + default List selectList(ProductRequirementPageReqVO reqVO) { + LambdaQueryWrapperX queryWrapper = buildQueryWrapper(reqVO); + return selectList(queryWrapper); + } + + /** + * 构建查询条件 + */ + private LambdaQueryWrapperX buildQueryWrapper(ProductRequirementPageReqVO reqVO) { LambdaQueryWrapperX queryWrapper = new LambdaQueryWrapperX<>(); // 标题模糊搜索 if (StringUtils.hasText(reqVO.getTitle())) { @@ -46,7 +62,7 @@ public interface ProductRequirementMapper extends BaseMapperX getRequirementTree(ProductRequirementPageReqVO pageReqVO) { - System.out.println("--------------"); - System.out.println(pageReqVO); - // 查询当前产品下的所有顶级需求 Long moduleId = pageReqVO.getModuleId(); Long productId = pageReqVO.getProductId(); - // 处理模块过滤条件:仅当选中具体模块(非“全部需求”)时,才递归加载子模块ID进行过滤 + // 处理模块过滤条件:仅当选中具体模块时,递归加载子模块ID进行过滤 if (moduleId != null) { pageReqVO.setModuleIds(getAllModuleIdsWithChildren(moduleId, productId)); - // 清空moduleId,避免与moduleIds冲突(Mapper中优先使用moduleIds做IN查询) pageReqVO.setModuleId(null); } - // 固定只查询父需求(parentId = 0L),子需求通过递归加载 - pageReqVO.setParentId(0L); - PageResult pageResult = requirementMapper.selectPage(pageReqVO); + // 清空parentId,查询所有符合条件的需求(不限层级) + pageReqVO.setParentId(null); - // 构建树形结构(子需求不计入分页) - List list = pageResult.getList().stream() - .map(this::buildRequirementRespVOWithChildren) + // 第一步:查询所有符合搜索条件的需求 + List matchedRequirements = requirementMapper.selectList(pageReqVO); + if (matchedRequirements.isEmpty()) { + return new PageResult<>(Collections.emptyList(), 0L); + } + + // 第二步:找出所有匹配需求的根节点ID,同时收集路径上的所有节点ID + Set rootIds = new HashSet<>(); + Set pathNodeIds = new HashSet<>(); + Map requirementCache = new HashMap<>(); + for (ProductRequirementDO req : matchedRequirements) { + requirementCache.put(req.getId(), req); + pathNodeIds.add(req.getId()); + Long rootId = findRootRequirementIdAndCollectPath(req, requirementCache, pathNodeIds); + rootIds.add(rootId); + } + + // 第三步:查询根需求详情并按创建时间倒排 + List rootRequirements = requirementMapper.selectBatchIds(rootIds); + rootRequirements.sort((a, b) -> b.getCreateTime().compareTo(a.getCreateTime())); + + // 第四步:对根节点列表进行内存分页 + int pageNo = pageReqVO.getPageNo() != null ? pageReqVO.getPageNo() : 1; + int pageSize = pageReqVO.getPageSize() != null ? pageReqVO.getPageSize() : 10; + int total = rootRequirements.size(); + int fromIndex = (pageNo - 1) * pageSize; + int toIndex = Math.min(fromIndex + pageSize, total); + + if (fromIndex >= total) { + return new PageResult<>(Collections.emptyList(), (long) total); + } + + List pagedRootRequirements = rootRequirements.subList(fromIndex, toIndex); + + // 第五步:构建树形结构(只包含路径上的节点) + List list = pagedRootRequirements.stream() + .map(req -> buildRequirementRespVOWithPathChildren(req, pathNodeIds)) .collect(Collectors.toList()); - return new PageResult<>(list, pageResult.getTotal()); + + return new PageResult<>(list, (long) total); + } + + /** + * 向上追溯需求的根节点ID,同时收集路径上的所有节点ID + * @param requirement 起始需求 + * @param cache 需求缓存(避免重复查询) + * @param pathNodeIds 路径节点ID集合(输出参数) + * @return 根节点ID(parentId = 0L 的需求ID) + */ + private Long findRootRequirementIdAndCollectPath(ProductRequirementDO requirement, + Map cache, + Set pathNodeIds) { + if (requirement.getParentId() == null || requirement.getParentId() == 0L) { + return requirement.getId(); + } + // 从缓存中查找父需求,如果没有则查询数据库 + ProductRequirementDO parent = cache.get(requirement.getParentId()); + if (parent == null) { + parent = requirementMapper.selectById(requirement.getParentId()); + if (parent != null) { + cache.put(parent.getId(), parent); + } + } + if (parent == null) { + // 父需求不存在(数据异常),返回当前需求作为根 + return requirement.getId(); + } + // 收集路径上的节点ID + pathNodeIds.add(parent.getId()); + return findRootRequirementIdAndCollectPath(parent, cache, pathNodeIds); + } + + /** + * 构建需求响应VO(只包含路径上的子需求) + * @param requirement 需求 + * @param pathNodeIds 路径节点ID集合 + * @return 需求响应VO + */ + private ProductRequirementRespVO buildRequirementRespVOWithPathChildren(ProductRequirementDO requirement, + Set pathNodeIds) { + ProductRequirementRespVO respVO = buildRequirementRespVO(requirement); + // 查询子需求 + List allChildren = requirementMapper.selectListByParentId(requirement.getId()); + // 只保留路径上的子需求 + List pathChildren = allChildren.stream() + .filter(child -> pathNodeIds.contains(child.getId())) + .toList(); + if (!pathChildren.isEmpty()) { + respVO.setChildren(pathChildren.stream() + .map(child -> buildRequirementRespVOWithPathChildren(child, pathNodeIds)) + .collect(Collectors.toList())); + } + return respVO; } /** @@ -607,21 +688,6 @@ public class ProductRequirementServiceImpl implements ProductRequirementService return respVO; } - /** - * 构建需求响应VO(含子需求) - */ - private ProductRequirementRespVO buildRequirementRespVOWithChildren(ProductRequirementDO requirement) { - ProductRequirementRespVO respVO = buildRequirementRespVO(requirement); - // 查询子需求 - List children = requirementMapper.selectListByParentId(requirement.getId()); - if (!children.isEmpty()) { - respVO.setChildren(children.stream() - .map(this::buildRequirementRespVOWithChildren) - .collect(Collectors.toList())); - } - return respVO; - } - /** * 构建模块树 */ @@ -723,7 +789,7 @@ public class ProductRequirementServiceImpl implements ProductRequirementService if (existModule == null) { return; } - if (moduleId == null || !existModule.getId().equals(moduleId)) { + if (!existModule.getId().equals(moduleId)) { throw exception(ErrorCodeConstants.REQUIREMENT_MODULE_NAME_DUPLICATE, moduleName.trim()); } }