farm模块-二级字典抽取

This commit is contained in:
顾君禹
2025-08-28 15:19:17 +08:00
parent fb76db876f
commit 04f1ec8c80
4 changed files with 141 additions and 57 deletions

View File

@@ -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.SpeciesLibraryPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibraryRespVO; 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.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.disasterdata.DisasterDataDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.farmingnamemaintenance.FarmingNameMaintenanceDO; import cn.iocoder.yudao.module.farm.dal.dataobject.farmingnamemaintenance.FarmingNameMaintenanceDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.farmingtypemaintenance.FarmingTypeMaintenanceDO; 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.speciesclassifylibrary.SpeciesClassifyLibraryService;
import cn.iocoder.yudao.module.farm.service.specieslibrary.SpeciesLibraryService; 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.sysDict.SysDictService;
import cn.iocoder.yudao.module.farm.service.twodict.TwoDictService;
import cn.iocoder.yudao.module.farm.utils.TreeStructureUtil; import cn.iocoder.yudao.module.farm.utils.TreeStructureUtil;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@@ -82,8 +85,9 @@ public class DictController {
private final ProductionPlanService productionPlanService; private final ProductionPlanService productionPlanService;
private final BaseInfoService baseInfoService; private final BaseInfoService baseInfoService;
private final FarmingTypeMaintenanceService farmingTypeMaintenanceService; 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.speciesLibraryService = speciesLibraryService;
this.speciesClassifyLibraryService = speciesClassifyLibraryService; this.speciesClassifyLibraryService = speciesClassifyLibraryService;
this.inputLibraryService = inputLibraryService; this.inputLibraryService = inputLibraryService;
@@ -92,6 +96,7 @@ public class DictController {
this.productionPlanService = productionPlanService; this.productionPlanService = productionPlanService;
this.baseInfoService = baseInfoService; this.baseInfoService = baseInfoService;
this.farmingTypeMaintenanceService = farmingTypeMaintenanceService; this.farmingTypeMaintenanceService = farmingTypeMaintenanceService;
this.twoDictService = twoDictService;
} }
// 农事类型 // 农事类型
@@ -290,14 +295,9 @@ public class DictController {
@Operation(summary = "字典数据维护-下拉框列表-三级物种类别") @Operation(summary = "字典数据维护-下拉框列表-三级物种类别")
@GetMapping("/list/three-library") @GetMapping("/list/three-library")
public CommonResult<List<SpeciesClassifyLibraryRespVO>> getTreeLibraryList() { public CommonResult<List<SpeciesThreeLevelTreeRespVO>> getTreeLibraryList() {
try { try {
// 获取物种生命周期 List<SpeciesThreeLevelTreeRespVO> threeList = speciesLibraryService.getSpeciesThreeLevelTree();
Map<String, String> lifeCycMap = speciesLibraryService.getSpeciesLibraryForLifeCycMap();
// 获取物种类别字典数据
List<SysDictDO> dictList = sysDictService.getByTypeCode(CommonConstants.DICT_TYPE_CODE_3);
// 使用工具类构建树结构
List<SpeciesClassifyLibraryRespVO> threeList = TreeStructureUtil.buildSpeciesClassifyTree(dictList,lifeCycMap);
return success(threeList); return success(threeList);
} catch (Exception e) { } catch (Exception e) {
log.error("获取三级物种类别列表失败", e); log.error("获取三级物种类别列表失败", e);

View File

@@ -135,7 +135,7 @@ public class ModelManagementServiceImpl implements ModelManagementService {
newModelCase.setType(CommonConstants.MODEL_TYPE_2); // 设置为引用案例类型 newModelCase.setType(CommonConstants.MODEL_TYPE_2); // 设置为引用案例类型
newModelCase.setTaskId(taskId); newModelCase.setTaskId(taskId);
newModelCase.setModelName(modelManagementDO.getModelName()); newModelCase.setModelName(modelManagementDO.getModelName());
newModelCase.setQuoteCount(0);
// 3. 保存新的模型引用案例 // 3. 保存新的模型引用案例
modelManagementMapper.insert(newModelCase); modelManagementMapper.insert(newModelCase);
@@ -202,8 +202,8 @@ public class ModelManagementServiceImpl implements ModelManagementService {
if (existing == null) { if (existing == null) {
return; return;
} }
SysDictThreeLvRespVO dictByField3Code = sysDictService.getDictByField3Code(existing.getSpeciesId()); SpeciesLibraryDO speciesLibrary = speciesLibraryService.getSpeciesLibrary(updateReqVO.getSpeciesId());
existing.setSpeciesName(dictByField3Code.getNames()); existing.setSpeciesName(speciesLibrary.getSpeciesName() + "/" + speciesLibrary.getCultivarName());
// 基础字段:仅当请求中非空时才覆盖 // 基础字段:仅当请求中非空时才覆盖
if (updateReqVO.getModelName() != null) existing.setModelName(updateReqVO.getModelName()); if (updateReqVO.getModelName() != null) existing.setModelName(updateReqVO.getModelName());
if (updateReqVO.getSpeciesId() != null) existing.setSpeciesId(updateReqVO.getSpeciesId()); if (updateReqVO.getSpeciesId() != null) existing.setSpeciesId(updateReqVO.getSpeciesId());

View File

@@ -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.SpeciesLibraryPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.specieslibrary.vo.SpeciesLibrarySaveReqVO; 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.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.modelmanagement.ModelManagementDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.specieslibrary.SpeciesLibraryDO; import cn.iocoder.yudao.module.farm.dal.dataobject.specieslibrary.SpeciesLibraryDO;
import cn.iocoder.yudao.module.farm.dal.mysql.modelmanagement.ModelManagementMapper; 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.dal.mysql.sysDict.SysDictDO;
import cn.iocoder.yudao.module.farm.enums.CommonConstants; import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.service.sysDict.SysDictService; 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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
@@ -24,8 +26,10 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -49,7 +53,8 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService {
private SysDictService sysDictService; private SysDictService sysDictService;
@Resource @Resource
private ModelManagementMapper modelManagementMapper; private ModelManagementMapper modelManagementMapper;
@Resource
private TwoDictService twoDictService;
@Override @Override
public String createSpeciesLibrary(SpeciesLibrarySaveReqVO createReqVO) { public String createSpeciesLibrary(SpeciesLibrarySaveReqVO createReqVO) {
@@ -233,30 +238,71 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService {
@Override @Override
public List<SpeciesThreeLevelTreeRespVO> getSpeciesThreeLevelTree() { public List<SpeciesThreeLevelTreeRespVO> getSpeciesThreeLevelTree() {
List<SpeciesLibraryDO> list = speciesLibraryMapper.selectList(); List<TwoDictTreeRespVO> dictTree = twoDictService.getTwoDictTree();
Map<String, Map<String, List<SpeciesLibraryDO>>> grouped = list.stream().collect(Collectors.groupingBy( if (dictTree == null || dictTree.isEmpty()) {
e -> splitSpeciesName(e.getSpeciesName(), 0), return new ArrayList<>();
Collectors.groupingBy(e -> splitSpeciesName(e.getSpeciesName(), 1)) }
));
return grouped.entrySet().stream().map(level1 -> { // 1级:parentId == null 的节点
SpeciesThreeLevelTreeRespVO n1 = new SpeciesThreeLevelTreeRespVO(); List<TwoDictTreeRespVO> level1Nodes = dictTree.stream()
n1.setName(level1.getKey()); .filter(n -> n != null && n.getParentId() == null)
List<SpeciesThreeLevelTreeRespVO> childrenLv2 = level1.getValue().entrySet().stream().map(level2 -> { .sorted(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo)))
SpeciesThreeLevelTreeRespVO n2 = new SpeciesThreeLevelTreeRespVO(); .collect(Collectors.toList());
n2.setName(level2.getKey());
List<SpeciesThreeLevelTreeRespVO> childrenLv3 = level2.getValue().stream().map(leaf -> { // 收集所有二级分类ID,一次性查询物种,避免 N+1
SpeciesThreeLevelTreeRespVO n3 = new SpeciesThreeLevelTreeRespVO(); List<Long> level2Ids = dictTree.stream()
n3.setName(leaf.getCultivarName()); .filter(n -> n != null && n.getParentId() != null) // 非根即二级(在当前两级分类中)
n3.setId(leaf.getId()); .map(TwoDictTreeRespVO::getId)
return n3; .filter(Objects::nonNull)
}).collect(Collectors.toList()); .collect(Collectors.toList());
n2.setChildren(childrenLv3);
return n2; Map<String, List<SpeciesLibraryDO>> categoryToSpeciesMap;
}).collect(Collectors.toList()); if (level2Ids.isEmpty()) {
n1.setChildren(childrenLv2); categoryToSpeciesMap = java.util.Collections.emptyMap();
return n1; } else {
}).collect(Collectors.toList()); level2Ids.forEach(level2Id -> {
});
}
List<SpeciesThreeLevelTreeRespVO> result = new ArrayList<>();
for (TwoDictTreeRespVO lvl1 : level1Nodes) {
SpeciesThreeLevelTreeRespVO lvl1Vo = new SpeciesThreeLevelTreeRespVO();
lvl1Vo.setName(lvl1.getName());
lvl1Vo.setId(lvl1.getId().toString());
List<SpeciesThreeLevelTreeRespVO> lvl2Vos = new ArrayList<>();
if (lvl1.getChildren() != null && !lvl1.getChildren().isEmpty()) {
// 二级按名称排序
List<TwoDictTreeRespVO> 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<SpeciesLibraryDO> qwAll = new LambdaQueryWrapper<>();
qwAll.eq(SpeciesLibraryDO::getCategory, lvl2.getId().toString());
qwAll.eq(SpeciesLibraryDO::getTenantId, String.valueOf(getLoginUser().getTenantId()));
List<SpeciesLibraryDO> speciesList = speciesLibraryMapper.selectList(qwAll);
List<SpeciesThreeLevelTreeRespVO> 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) { private String splitSpeciesName(String speciesName, int index) {
@@ -290,7 +336,7 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService {
} }
} }
private List<SpeciesAndModelTreeRespVO.ModelInfoRespVO> getModelList(String speciesId) { private List<SpeciesAndModelTreeRespVO.ModelInfoRespVO> getModelList(String speciesId) {
LambdaQueryWrapper<ModelManagementDO> lambdaQueryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<ModelManagementDO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(ModelManagementDO::getTenantId, getLoginUser().getTenantId()); lambdaQueryWrapper.eq(ModelManagementDO::getTenantId, getLoginUser().getTenantId());
lambdaQueryWrapper.eq(ModelManagementDO::getType, CommonConstants.MODEL_TYPE_1); lambdaQueryWrapper.eq(ModelManagementDO::getType, CommonConstants.MODEL_TYPE_1);

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.farm.utils; 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.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 cn.iocoder.yudao.module.farm.dal.mysql.sysDict.SysDictDO;
import java.util.*; import java.util.*;
@@ -17,35 +18,72 @@ public class TreeStructureUtil {
/** /**
* 构建物种类别树结构(支持三级分类) * 构建物种类别树结构(支持三级分类)
* * 说明:该方法基于 TwoDictTreeRespVO 的树(id/name/children)来生成
* @param dictList 字典数据列表 * SpeciesClassifyLibraryRespVO 的三级树。其中:
* @return 树形结构列表 * - 一级:root 节点(parentId == null)
* - 二级:root.children
* - 三级:child.children,并在第三级填充生命周期(lifeCycle)
*/ */
public static List<SpeciesClassifyLibraryRespVO> buildSpeciesClassifyTree(List<SysDictDO> dictList, Map<String, String> lifeCycMap) { public static List<SpeciesClassifyLibraryRespVO> buildSpeciesClassifyTree(List<TwoDictTreeRespVO> dictList,
Map<String, String> lifeCycMap) {
if (dictList == null || dictList.isEmpty()) { if (dictList == null || dictList.isEmpty()) {
return new ArrayList<>(); return new ArrayList<>();
} }
try { // 兜底,避免 NPE
// 按一级分类分组 Map<String, String> safeLifeMap = lifeCycMap != null ? lifeCycMap : Collections.emptyMap();
Map<String, List<SysDictDO>> groupedByLevel1 = dictList.stream()
.filter(dict -> isValidLevel1Node(dict))
.collect(Collectors.groupingBy(
SysDictDO::getField1Code,
Collectors.toList()
));
// 构建三级树形结构 // 找到所有根节点(parentId == null)
return groupedByLevel1.entrySet().stream() List<TwoDictTreeRespVO> level1Nodes = dictList.stream()
.map(entry -> buildLevel1Node(entry.getKey(), entry.getValue(), dictList,lifeCycMap)) .filter(Objects::nonNull)
.filter(Objects::nonNull) .filter(n -> n.getParentId() == null)
.sorted(Comparator.comparing(SpeciesClassifyLibraryRespVO::getSpeciesClassName)) .sorted(Comparator.comparing(TwoDictTreeRespVO::getName, Comparator.nullsLast(String::compareTo)))
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch (Exception e) { List<SpeciesClassifyLibraryRespVO> result = new ArrayList<>();
// 记录错误日志,返回空列表 for (TwoDictTreeRespVO lvl1 : level1Nodes) {
return new ArrayList<>(); if (lvl1.getId() == null || lvl1.getName() == null || lvl1.getName().trim().isEmpty()) {
continue;
}
SpeciesClassifyLibraryRespVO lvl1Vo = new SpeciesClassifyLibraryRespVO(String.valueOf(lvl1.getId()), lvl1.getName());
// 二级
List<SpeciesClassifyLibraryRespVO> lvl2Vos = new ArrayList<>();
List<TwoDictTreeRespVO> 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<SpeciesClassifyLibraryRespVO> lvl3Vos = new ArrayList<>();
List<TwoDictTreeRespVO> 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;
} }
/** /**