From 04f1ec8c802d97cd08b5a6391af3f351df095aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A1=BE=E5=90=9B=E7=A6=B9?= <2673609096@qq.com> Date: Thu, 28 Aug 2025 15:19:17 +0800 Subject: [PATCH] =?UTF-8?q?farm=E6=A8=A1=E5=9D=97-=E4=BA=8C=E7=BA=A7?= =?UTF-8?q?=E5=AD=97=E5=85=B8=E6=8A=BD=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/admin/dict/DictController.java | 16 ++-- .../ModelManagementServiceImpl.java | 6 +- .../SpeciesLibraryServiceImpl.java | 96 ++++++++++++++----- .../module/farm/utils/TreeStructureUtil.java | 80 ++++++++++++---- 4 files changed, 141 insertions(+), 57 deletions(-) diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java index 19e889cb..8053c83e 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java @@ -26,6 +26,8 @@ import cn.iocoder.yudao.module.farm.controller.admin.inputlibrary.vo.InputLibrar import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibraryPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibraryRespVO; import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibrarySaveReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesThreeLevelTreeRespVO; +import cn.iocoder.yudao.module.farm.controller.admin.twodict.vo.TwoDictTreeRespVO; import cn.iocoder.yudao.module.farm.dal.dataobject.disasterdata.DisasterDataDO; import cn.iocoder.yudao.module.farm.dal.dataobject.farmingnamemaintenance.FarmingNameMaintenanceDO; import cn.iocoder.yudao.module.farm.dal.dataobject.farmingtypemaintenance.FarmingTypeMaintenanceDO; @@ -41,6 +43,7 @@ import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService import cn.iocoder.yudao.module.farm.service.speciesclassifylibrary.SpeciesClassifyLibraryService; import cn.iocoder.yudao.module.farm.service.specieslibrary.SpeciesLibraryService; import cn.iocoder.yudao.module.farm.service.sysDict.SysDictService; +import cn.iocoder.yudao.module.farm.service.twodict.TwoDictService; import cn.iocoder.yudao.module.farm.utils.TreeStructureUtil; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -82,8 +85,9 @@ public class DictController { private final ProductionPlanService productionPlanService; private final BaseInfoService baseInfoService; private final FarmingTypeMaintenanceService farmingTypeMaintenanceService; + private final TwoDictService twoDictService; - public DictController(SpeciesLibraryService speciesLibraryService, SpeciesClassifyLibraryService speciesClassifyLibraryService, InputLibraryService inputLibraryService, DisasterDataService disasterDataService, SysDictService sysDictService, ProductionPlanService productionPlanService, BaseInfoService baseInfoService, FarmingTypeMaintenanceService farmingTypeMaintenanceService) { + public DictController(SpeciesLibraryService speciesLibraryService, SpeciesClassifyLibraryService speciesClassifyLibraryService, InputLibraryService inputLibraryService, DisasterDataService disasterDataService, SysDictService sysDictService, ProductionPlanService productionPlanService, BaseInfoService baseInfoService, FarmingTypeMaintenanceService farmingTypeMaintenanceService, TwoDictService twoDictService) { this.speciesLibraryService = speciesLibraryService; this.speciesClassifyLibraryService = speciesClassifyLibraryService; this.inputLibraryService = inputLibraryService; @@ -92,6 +96,7 @@ public class DictController { this.productionPlanService = productionPlanService; this.baseInfoService = baseInfoService; this.farmingTypeMaintenanceService = farmingTypeMaintenanceService; + this.twoDictService = twoDictService; } // 农事类型 @@ -290,14 +295,9 @@ public class DictController { @Operation(summary = "字典数据维护-下拉框列表-三级物种类别") @GetMapping("/list/three-library") - public CommonResult> getTreeLibraryList() { + public CommonResult> getTreeLibraryList() { try { - // 获取物种生命周期 - Map lifeCycMap = speciesLibraryService.getSpeciesLibraryForLifeCycMap(); - // 获取物种类别字典数据 - List dictList = sysDictService.getByTypeCode(CommonConstants.DICT_TYPE_CODE_3); - // 使用工具类构建树结构 - List threeList = TreeStructureUtil.buildSpeciesClassifyTree(dictList,lifeCycMap); + List threeList = speciesLibraryService.getSpeciesThreeLevelTree(); return success(threeList); } catch (Exception e) { log.error("获取三级物种类别列表失败", e); diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/modelmanagement/ModelManagementServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/modelmanagement/ModelManagementServiceImpl.java index bdadc5f5..5eb5d9fb 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/modelmanagement/ModelManagementServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/modelmanagement/ModelManagementServiceImpl.java @@ -135,7 +135,7 @@ public class ModelManagementServiceImpl implements ModelManagementService { newModelCase.setType(CommonConstants.MODEL_TYPE_2); // 设置为引用案例类型 newModelCase.setTaskId(taskId); newModelCase.setModelName(modelManagementDO.getModelName()); - + newModelCase.setQuoteCount(0); // 3. 保存新的模型引用案例 modelManagementMapper.insert(newModelCase); @@ -202,8 +202,8 @@ public class ModelManagementServiceImpl implements ModelManagementService { if (existing == null) { return; } - SysDictThreeLvRespVO dictByField3Code = sysDictService.getDictByField3Code(existing.getSpeciesId()); - existing.setSpeciesName(dictByField3Code.getNames()); + SpeciesLibraryDO speciesLibrary = speciesLibraryService.getSpeciesLibrary(updateReqVO.getSpeciesId()); + existing.setSpeciesName(speciesLibrary.getSpeciesName() + "/" + speciesLibrary.getCultivarName()); // 基础字段:仅当请求中非空时才覆盖 if (updateReqVO.getModelName() != null) existing.setModelName(updateReqVO.getModelName()); if (updateReqVO.getSpeciesId() != null) existing.setSpeciesId(updateReqVO.getSpeciesId()); diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java index bc1b2842..cbf1d7c8 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesAn import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibraryPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibrarySaveReqVO; import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesThreeLevelTreeRespVO; +import cn.iocoder.yudao.module.farm.controller.admin.twodict.vo.TwoDictTreeRespVO; import cn.iocoder.yudao.module.farm.dal.dataobject.modelmanagement.ModelManagementDO; import cn.iocoder.yudao.module.farm.dal.dataobject.specieslibrary.SpeciesLibraryDO; import cn.iocoder.yudao.module.farm.dal.mysql.modelmanagement.ModelManagementMapper; @@ -17,6 +18,7 @@ import cn.iocoder.yudao.module.farm.dal.mysql.specieslibrary.SpeciesLibraryMappe import cn.iocoder.yudao.module.farm.dal.mysql.sysDict.SysDictDO; import cn.iocoder.yudao.module.farm.enums.CommonConstants; import cn.iocoder.yudao.module.farm.service.sysDict.SysDictService; +import cn.iocoder.yudao.module.farm.service.twodict.TwoDictService; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import jakarta.annotation.Resource; import org.apache.commons.lang3.ObjectUtils; @@ -24,8 +26,10 @@ import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -49,7 +53,8 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService { private SysDictService sysDictService; @Resource private ModelManagementMapper modelManagementMapper; - + @Resource + private TwoDictService twoDictService; @Override public String createSpeciesLibrary(SpeciesLibrarySaveReqVO createReqVO) { @@ -233,30 +238,71 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService { @Override public List getSpeciesThreeLevelTree() { - List list = speciesLibraryMapper.selectList(); - Map>> grouped = list.stream().collect(Collectors.groupingBy( - e -> splitSpeciesName(e.getSpeciesName(), 0), - Collectors.groupingBy(e -> splitSpeciesName(e.getSpeciesName(), 1)) - )); + List dictTree = twoDictService.getTwoDictTree(); + if (dictTree == null || dictTree.isEmpty()) { + return new ArrayList<>(); + } - return grouped.entrySet().stream().map(level1 -> { - SpeciesThreeLevelTreeRespVO n1 = new SpeciesThreeLevelTreeRespVO(); - n1.setName(level1.getKey()); - List childrenLv2 = level1.getValue().entrySet().stream().map(level2 -> { - SpeciesThreeLevelTreeRespVO n2 = new SpeciesThreeLevelTreeRespVO(); - n2.setName(level2.getKey()); - List childrenLv3 = level2.getValue().stream().map(leaf -> { - SpeciesThreeLevelTreeRespVO n3 = new SpeciesThreeLevelTreeRespVO(); - n3.setName(leaf.getCultivarName()); - n3.setId(leaf.getId()); - return n3; - }).collect(Collectors.toList()); - n2.setChildren(childrenLv3); - return n2; - }).collect(Collectors.toList()); - n1.setChildren(childrenLv2); - return n1; - }).collect(Collectors.toList()); + // 1级:parentId == null 的节点 + List level1Nodes = dictTree.stream() + .filter(n -> n != null && n.getParentId() == null) + .sorted(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo))) + .collect(Collectors.toList()); + + // 收集所有二级分类ID,一次性查询物种,避免 N+1 + List level2Ids = dictTree.stream() + .filter(n -> n != null && n.getParentId() != null) // 非根即二级(在当前两级分类中) + .map(TwoDictTreeRespVO::getId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + Map> categoryToSpeciesMap; + if (level2Ids.isEmpty()) { + categoryToSpeciesMap = java.util.Collections.emptyMap(); + } else { + level2Ids.forEach(level2Id -> { + + }); + + + } + + List result = new ArrayList<>(); + for (TwoDictTreeRespVO lvl1 : level1Nodes) { + SpeciesThreeLevelTreeRespVO lvl1Vo = new SpeciesThreeLevelTreeRespVO(); + lvl1Vo.setName(lvl1.getName()); + lvl1Vo.setId(lvl1.getId().toString()); + List lvl2Vos = new ArrayList<>(); + if (lvl1.getChildren() != null && !lvl1.getChildren().isEmpty()) { + // 二级按名称排序 + List lvl2Children = new ArrayList<>(lvl1.getChildren()); + lvl2Children.sort(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo))); + for (TwoDictTreeRespVO lvl2 : lvl2Children) { + SpeciesThreeLevelTreeRespVO lvl2Vo = new SpeciesThreeLevelTreeRespVO(); + lvl2Vo.setName(lvl2.getName()); + lvl2Vo.setId(lvl2.getId().toString()); + // 三级:该二级分类下的品种(物种库) + LambdaQueryWrapper qwAll = new LambdaQueryWrapper<>(); + qwAll.eq(SpeciesLibraryDO::getCategory, lvl2.getId().toString()); + qwAll.eq(SpeciesLibraryDO::getTenantId, String.valueOf(getLoginUser().getTenantId())); + List speciesList = speciesLibraryMapper.selectList(qwAll); + + + List lvl3Vos = new ArrayList<>(speciesList.size()); + for (SpeciesLibraryDO sp : speciesList) { + SpeciesThreeLevelTreeRespVO lvl3Vo = new SpeciesThreeLevelTreeRespVO(); + lvl3Vo.setName(sp.getCultivarName()); + lvl3Vo.setId(sp.getId()); + lvl3Vos.add(lvl3Vo); + } + lvl2Vo.setChildren(lvl3Vos); + lvl2Vos.add(lvl2Vo); + } + } + lvl1Vo.setChildren(lvl2Vos); + result.add(lvl1Vo); + } + return result; } private String splitSpeciesName(String speciesName, int index) { @@ -290,7 +336,7 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService { } } - private List getModelList(String speciesId) { + private List getModelList(String speciesId) { LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(ModelManagementDO::getTenantId, getLoginUser().getTenantId()); lambdaQueryWrapper.eq(ModelManagementDO::getType, CommonConstants.MODEL_TYPE_1); diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/TreeStructureUtil.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/TreeStructureUtil.java index 4113bb62..4fdbc51a 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/TreeStructureUtil.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/TreeStructureUtil.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.farm.utils; import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.SpeciesClassifyLibraryRespVO; +import cn.iocoder.yudao.module.farm.controller.admin.twodict.vo.TwoDictTreeRespVO; import cn.iocoder.yudao.module.farm.dal.mysql.sysDict.SysDictDO; import java.util.*; @@ -17,35 +18,72 @@ public class TreeStructureUtil { /** * 构建物种类别树结构(支持三级分类) - * - * @param dictList 字典数据列表 - * @return 树形结构列表 + * 说明:该方法基于 TwoDictTreeRespVO 的树(id/name/children)来生成 + * SpeciesClassifyLibraryRespVO 的三级树。其中: + * - 一级:root 节点(parentId == null) + * - 二级:root.children + * - 三级:child.children,并在第三级填充生命周期(lifeCycle) */ - public static List buildSpeciesClassifyTree(List dictList, Map lifeCycMap) { + public static List buildSpeciesClassifyTree(List dictList, + Map lifeCycMap) { if (dictList == null || dictList.isEmpty()) { return new ArrayList<>(); } - try { - // 按一级分类分组 - Map> groupedByLevel1 = dictList.stream() - .filter(dict -> isValidLevel1Node(dict)) - .collect(Collectors.groupingBy( - SysDictDO::getField1Code, - Collectors.toList() - )); + // 兜底,避免 NPE + Map safeLifeMap = lifeCycMap != null ? lifeCycMap : Collections.emptyMap(); - // 构建三级树形结构 - return groupedByLevel1.entrySet().stream() - .map(entry -> buildLevel1Node(entry.getKey(), entry.getValue(), dictList,lifeCycMap)) - .filter(Objects::nonNull) - .sorted(Comparator.comparing(SpeciesClassifyLibraryRespVO::getSpeciesClassName)) - .collect(Collectors.toList()); + // 找到所有根节点(parentId == null) + List level1Nodes = dictList.stream() + .filter(Objects::nonNull) + .filter(n -> n.getParentId() == null) + .sorted(Comparator.comparing(TwoDictTreeRespVO::getName, Comparator.nullsLast(String::compareTo))) + .collect(Collectors.toList()); - } catch (Exception e) { - // 记录错误日志,返回空列表 - return new ArrayList<>(); + List result = new ArrayList<>(); + for (TwoDictTreeRespVO lvl1 : level1Nodes) { + if (lvl1.getId() == null || lvl1.getName() == null || lvl1.getName().trim().isEmpty()) { + continue; + } + SpeciesClassifyLibraryRespVO lvl1Vo = new SpeciesClassifyLibraryRespVO(String.valueOf(lvl1.getId()), lvl1.getName()); + + // 二级 + List lvl2Vos = new ArrayList<>(); + List lvl2Children = lvl1.getChildren(); + if (lvl2Children != null && !lvl2Children.isEmpty()) { + // 按名称排序,提升观感 + lvl2Children.sort(Comparator.comparing(TwoDictTreeRespVO::getName, Comparator.nullsLast(String::compareTo))); + for (TwoDictTreeRespVO lvl2 : lvl2Children) { + if (lvl2 == null || lvl2.getId() == null || lvl2.getName() == null || lvl2.getName().trim().isEmpty()) { + continue; + } + SpeciesClassifyLibraryRespVO lvl2Vo = new SpeciesClassifyLibraryRespVO(String.valueOf(lvl2.getId()), lvl2.getName()); + + // 三级 + List lvl3Vos = new ArrayList<>(); + List lvl3Children = lvl2.getChildren(); + if (lvl3Children != null && !lvl3Children.isEmpty()) { + lvl3Children.sort(Comparator.comparing(TwoDictTreeRespVO::getName, Comparator.nullsLast(String::compareTo))); + for (TwoDictTreeRespVO lvl3 : lvl3Children) { + if (lvl3 == null || lvl3.getId() == null || lvl3.getName() == null || lvl3.getName().trim().isEmpty()) { + continue; + } + // lifeCycMap 的 key 为第三级数据的 ID + String lifeCycle = safeLifeMap.get(String.valueOf(lvl3.getId())); + lvl3Vos.add(new SpeciesClassifyLibraryRespVO(String.valueOf(lvl3.getId()), lvl3.getName(), lifeCycle)); + } + } + lvl2Vo.setChildren(lvl3Vos); + lvl2Vos.add(lvl2Vo); + } + } + lvl1Vo.setChildren(lvl2Vos); + result.add(lvl1Vo); } + + // 一级按名称排序 + result.sort(Comparator.comparing(SpeciesClassifyLibraryRespVO::getSpeciesClassName, Comparator.nullsLast(String::compareTo))); + return result; } /**