farm模块-优化三级树结构

This commit is contained in:
顾君禹
2025-08-23 19:41:29 +08:00
parent 7ec388151c
commit f69c840307
13 changed files with 526 additions and 140 deletions

View File

@@ -3,7 +3,9 @@ package cn.iocoder.yudao.module.farm.controller.admin.dict;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.*;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.CommonDictRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.FarmingTypeRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.SpeciesClassifyLibraryRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.sys.SysDictRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.sys.SysDictTypeCodeRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.disasterdata.vo.DisasterDataPageReqVO;
@@ -25,7 +27,6 @@ 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;
import cn.iocoder.yudao.module.farm.dal.dataobject.inputlibrary.InputLibraryDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.speciesclassifylibrary.SpeciesClassifyLibraryDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.specieslibrary.SpeciesLibraryDO;
import cn.iocoder.yudao.module.farm.dal.mysql.sysDict.SysDictDO;
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
@@ -36,15 +37,18 @@ import cn.iocoder.yudao.module.farm.service.inputlibrary.InputLibraryService;
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.utils.TreeStructureUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.redisson.misc.Hash;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@@ -64,6 +68,7 @@ import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@RestController
@RequestMapping("/farm/management-center/dict")
@Validated
@Slf4j
public class DictController {
private final FarmingTypeMaintenanceService farmingTypeMaintenanceService;
@@ -275,34 +280,17 @@ public class DictController {
@Operation(summary = "字典数据维护-下拉框列表-物种类别")
@GetMapping("/list/species-classify-library")
public CommonResult<List<SpeciesClassifyLibraryRespVO>> getSpeciesClassifyLibraryList() {
List<SysDictDO> list = sysDictService.getByTypeCode(CommonConstants.DICT_TYPE_CODE_3);
Map<String, String> parentMap = list.stream()
.collect(Collectors.toMap(
SysDictDO::getField1Code, // key: field1Code
SysDictDO::getField1Name, // value: field1Name
(existing, replacement) -> existing // 处理重复key,保留现有值
));
List<SpeciesClassifyLibraryRespVO> parentList = new ArrayList<>();
for (Map.Entry<String, String> entry : parentMap.entrySet()) {
String key = entry.getKey();
SpeciesClassifyLibraryRespVO pVO = new SpeciesClassifyLibraryRespVO(key, entry.getValue());
List<SpeciesClassifyLibraryRespVO> childList = new ArrayList<>();
for (SysDictDO e : list) {
if (e.getField1Code().equals(key)) {
childList.add(new SpeciesClassifyLibraryRespVO(e.getField2Code(),e.getField2Name()));
try {
// 获取物种类别字典数据
List<SysDictDO> dictList = sysDictService.getByTypeCode(CommonConstants.DICT_TYPE_CODE_3);
// 使用工具类构建树结构
List<SpeciesClassifyLibraryRespVO> treeList = TreeStructureUtil.buildSpeciesClassifyTree(dictList);
return success(treeList);
} catch (Exception e) {
log.error("获取物种类别列表失败", e);
return success(new ArrayList<>());
}
}
pVO.setChildren(childList);
parentList.add(pVO);
}
return success(parentList);
}
@Operation(summary = "字典数据维护-下拉框列表-通用字典分类查询")
@GetMapping("/list/{dictTypeCode}")
@@ -319,15 +307,6 @@ public class DictController {
}
@Operation(summary = "字典数据维护-下拉框列表-投入品类型")
@GetMapping("/list/invest-goods")
public CommonResult<List<CommonDictRespVO>> getInvestGoodsList() {
@@ -442,7 +421,4 @@ public class DictController {
}
}

View File

@@ -72,6 +72,27 @@ public class DisasterDataDO extends BaseDO {
* 删除状态 (1:已删除;2:未删除)
*/
private Integer useStatus;
/**
* 基地id
*/
private String baseId;
/**
* 基地
*/
private String baseName;
/**
* 地块ID
*/
private String plotId;
/**
* 地块
*/
private String plotName;
private String tenantId;
/**
* 获取图片集合
*/

View File

@@ -33,7 +33,7 @@ public class CommonConstants {
// 模型类型 (1:模型模板; 2:引用案例)
public final static Integer MODEL_TYPE_1 = 1;
public final static Integer MODEL_TYPE_2 = 1;
public final static Integer MODEL_TYPE_2 = 2;
/**
* 字典类型名称

View File

@@ -8,11 +8,20 @@ import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.Produc
import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanSaveReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanUpdateReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.farmingrecord.vo.FarmingRecordSaveReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.farmingrecordinput.vo.FarmingRecordInputSaveReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelcycle.vo.ModelCycleRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelfarmingoperation.vo.ModelFarmingOperationRespVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.farmingrecord.FarmingRecordDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.farmingrecordinput.FarmingRecordInputDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.modelfarmingoperationinput.ModelFarmingOperationInputDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.productionplan.ProductionPlanDO;
import cn.iocoder.yudao.module.farm.dal.mysql.productionplan.ProductionPlanMapper;
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.service.cultivationarea.CultivationAreaService;
import cn.iocoder.yudao.module.farm.service.farmingrecord.FarmingRecordService;
import cn.iocoder.yudao.module.farm.service.farmingrecordinput.FarmingRecordInputService;
import cn.iocoder.yudao.module.farm.service.modelmanagement.ModelManagementService;
import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService;
import cn.iocoder.yudao.module.farm.utils.StrHelperUtil;
@@ -20,6 +29,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -38,10 +49,17 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
private final ProductionPlanMapper productionPlanMapper;
private final ModelManagementService modelManagementService;
private final FarmingRecordService farmingRecordService;
private final FarmingRecordInputService farmingRecordInputService;
public CropFarmingCenterServiceImpl(ProductionPlanMapper productionPlanMapper, ModelManagementService modelManagementService) {
public CropFarmingCenterServiceImpl(ProductionPlanMapper productionPlanMapper,
ModelManagementService modelManagementService,
FarmingRecordService farmingRecordService,
FarmingRecordInputService farmingRecordInputService) {
this.productionPlanMapper = productionPlanMapper;
this.modelManagementService = modelManagementService;
this.farmingRecordService = farmingRecordService;
this.farmingRecordInputService = farmingRecordInputService;
}
@Override
@@ -49,7 +67,7 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
String taskId = IdUtil.fastUUID();
String speciesModelId = reqVO.getSpeciesModelId();
// 创建模型案例 todo
// 创建模型案例
speciesModelId = modelManagementService.createModelManagementCase(speciesModelId, taskId);
if (speciesModelId.equals("")) {
return;
@@ -82,7 +100,6 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
obj.setPlotName(e.getPlotName());
obj.setTenantId(e.getTenantId());
// 随机字符串 + 地块名称
obj.setPlanNumber(StrHelperUtil.generate() + "-" + e.getPlotName());
obj.setId(taskId);
@@ -90,6 +107,83 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
}
productionPlanMapper.insertBatch(list);
// 根据模型生成农事记录
for (ProductionPlanSaveReqVO.CultivationArea e : cultivationAreaList) {
generateFarmingRecordsFromModel(speciesModelId, taskId, e.getPlantingDate(), e.getBaseId(), e.getBaseName(), e.getPlotId(), e.getPlotName(), e.getTenantId());
}
}
/**
* 根据模型生成农事记录
*
* @param modelId 模型ID
* @param productionPlanId 生产计划ID
* @param plantingDate 种植日期
* @param baseId 基地ID
* @param baseName 基地名称
* @param plotId 地块ID
* @param plotName 地块名称
* @param tenantId 租户ID
*/
private void generateFarmingRecordsFromModel(String modelId, String productionPlanId, LocalDate plantingDate,
String baseId, String baseName, String plotId, String plotName, String tenantId) {
// 获取模型信息
ModelManagementRespVO model = modelManagementService.getModelManagement(modelId);
if (model == null || model.getModelCycles() == null) {
log.warn("模型信息为空,无法生成农事记录,modelId: {}", modelId);
return;
}
// 遍历模型周期,生成农事记录
for (ModelCycleRespVO cycle : model.getModelCycles()) {
// 计算农事操作时间(基于种植日期和周期天数)
LocalDate operationDate = plantingDate.plusDays(cycle.getStage());
// 生成农事操作记录
if (cycle.getFarmingOperationDOS() != null) {
for (ModelFarmingOperationRespVO operation : cycle.getFarmingOperationDOS()) {
// 创建农事记录
FarmingRecordSaveReqVO farmingRecordReq = new FarmingRecordSaveReqVO();
farmingRecordReq.setTaskType("农事操作");
farmingRecordReq.setTaskName(operation.getFarmingName());
farmingRecordReq.setTaskScope(cycle.getName());
farmingRecordReq.setTaskTime(operationDate.atStartOfDay());
farmingRecordReq.setPlotId(plotId);
farmingRecordReq.setProductionPlanId(productionPlanId);
farmingRecordReq.setExecutor("系统生成");
farmingRecordReq.setActualLaborCost(operation.getWorkersNumber());
farmingRecordReq.setFeedbackNotes(operation.getDescription());
farmingRecordReq.setBaseId(baseId);
farmingRecordReq.setBaseName(baseName);
farmingRecordReq.setPlotName(plotName);
farmingRecordReq.setTenantId(tenantId);
String farmingRecordId = farmingRecordService.createFarmingRecord(farmingRecordReq);
// 生成农事操作投入品记录
if (operation.getFarmingOperationInputDOS() != null) {
for (ModelFarmingOperationInputDO input : operation.getFarmingOperationInputDOS()) {
FarmingRecordInputSaveReqVO inputReq = new FarmingRecordInputSaveReqVO();
inputReq.setFarmRecordId(farmingRecordId);
inputReq.setInputParentCategory("农事操作投入品");
inputReq.setInputChildCategory(input.getInputsId());
inputReq.setDilutionRatio(input.getDiluted());
inputReq.setDosage(input.getDose());
inputReq.setUsage(input.getUsage());
inputReq.setBaseId(baseId);
inputReq.setBaseName(baseName);
inputReq.setPlotId(plotId);
inputReq.setPlotName(plotName);
inputReq.setTenantId(tenantId);
farmingRecordInputService.createFarmingRecordInput(inputReq);
}
}
}
}
}
log.info("成功为生产计划 {} 生成农事记录,基于模型 {}", productionPlanId, modelId);
}
@Override

View File

@@ -41,7 +41,6 @@ public class DisasterDataServiceImpl implements DisasterDataService {
@Override
public String createDisasterData(DisasterDataSaveReqVO createReqVO) {
// 插入
DisasterDataDO disasterData = BeanUtils.toBean(createReqVO, DisasterDataDO.class);
// 将图片集合转换为数据库存储的字符串,仅当前端传了列表时进行转换
@@ -51,6 +50,7 @@ public class DisasterDataServiceImpl implements DisasterDataService {
disasterData.setId(IdUtil.fastUUID());
disasterData.setCreateTime(LocalDateTime.now());
disasterData.setCreator(getLoginUser().getId().toString());
disasterData.setTenantId(getLoginUser().getTenantId().toString());
disasterDataMapper.insert(disasterData);
// 返回

View File

@@ -1,26 +1,20 @@
package cn.iocoder.yudao.module.farm.service.fertilizerindex;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.farm.controller.admin.fertilizerindex.vo.FertilizerIndexPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.fertilizerindex.vo.FertilizerIndexSaveReqVO;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import cn.iocoder.yudao.module.farm.dal.dataobject.fertilizerindex.FertilizerIndexDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.farm.dal.mysql.fertilizerindex.FertilizerIndexMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.FERTILIZER_INDEX_NOT_EXISTS;
@@ -42,6 +36,7 @@ public class FertilizerIndexServiceImpl implements FertilizerIndexService {
// 插入
FertilizerIndexDO fertilizerIndex = BeanUtils.toBean(createReqVO, FertilizerIndexDO.class);
fertilizerIndex.setTenantId(String.valueOf(user.getTenantId()));
fertilizerIndex.setId(IdUtil.fastUUID());
fertilizerIndexMapper.insert(fertilizerIndex);
// 返回

View File

@@ -74,7 +74,7 @@ public class ModelManagementServiceImpl implements ModelManagementService {
@Override
public String createModelManagementCase(String id, String taskId) {
// 1. 查询原模型(类型为模型模板)
ModelManagementDO modelManagementDO = modelManagementMapper.selectOne(
ModelManagementDO::getId, id,
ModelManagementDO::getType, CommonConstants.MODEL_TYPE_1
@@ -84,12 +84,70 @@ public class ModelManagementServiceImpl implements ModelManagementService {
return "";
}
ModelManagementRespVO modelManagement = this.getModelManagement(modelManagementDO.getId());
// 2. 创建新的模型引用案例
ModelManagementDO newModelCase = BeanUtils.toBean(modelManagementDO, ModelManagementDO.class);
String newModelId = IdUtil.fastUUID();
newModelCase.setId(newModelId);
newModelCase.setType(CommonConstants.MODEL_TYPE_2); // 设置为引用案例类型
newModelCase.setTaskId(taskId);
newModelCase.setModelName(modelManagementDO.getModelName());
// 3. 保存新的模型引用案例
modelManagementMapper.insert(newModelCase);
// 4. 复制模型周期及其子集
List<ModelCycleDO> originalCycles = modelCycleMapper.selectListByModelId(id);
for (ModelCycleDO originalCycle : originalCycles) {
// 复制周期
ModelCycleDO newCycle = BeanUtils.toBean(originalCycle, ModelCycleDO.class);
String newCycleId = IdUtil.fastUUID();
newCycle.setId(newCycleId);
newCycle.setModelId(newModelId);
modelCycleMapper.insert(newCycle);
// 将新建的的模型id返回
return null;
// 复制环境指标
List<ModelEnvironmentIndexDO> environmentIndexes = modelEnvironmentIndexMapper.selectByCycleId(originalCycle.getId());
for (ModelEnvironmentIndexDO envIndex : environmentIndexes) {
envIndex.setId(IdUtil.fastUUID());
envIndex.setCycleId(newCycleId);
modelEnvironmentIndexMapper.insert(envIndex);
}
// 复制气象灾害
List<ModelWeatherDisasterDO> weatherDisasters = modelWeatherDisasterMapper.selectByCycleId(originalCycle.getId());
for (ModelWeatherDisasterDO weatherDisaster : weatherDisasters) {
weatherDisaster.setId(IdUtil.fastUUID());
weatherDisaster.setCycleId(newCycleId);
modelWeatherDisasterMapper.insert(weatherDisaster);
}
// 复制病虫草灾害
List<ModelPestDiseaseWeedDO> pestDiseaseWeeds = modelPestDiseaseWeedMapper.selectByCycleId(originalCycle.getId());
for (ModelPestDiseaseWeedDO pestDiseaseWeed : pestDiseaseWeeds) {
pestDiseaseWeed.setId(IdUtil.fastUUID());
pestDiseaseWeed.setCycleId(newCycleId);
modelPestDiseaseWeedMapper.insert(pestDiseaseWeed);
}
// 复制农事操作
List<ModelFarmingOperationDO> farmingOperations = modelFarmingOperationMapper.selectByCycleId(originalCycle.getId());
for (ModelFarmingOperationDO farmingOperation : farmingOperations) {
String newFarmingId = IdUtil.fastUUID();
farmingOperation.setId(newFarmingId);
farmingOperation.setCycleId(newCycleId);
modelFarmingOperationMapper.insert(farmingOperation);
// 复制农事操作投入品
List<ModelFarmingOperationInputDO> farmingOperationInputs = modelFarmingOperationInputMapper.selectByFarmingId(farmingOperation.getId());
for (ModelFarmingOperationInputDO farmingOperationInput : farmingOperationInputs) {
farmingOperationInput.setId(IdUtil.fastUUID());
farmingOperationInput.setFarmingId(newFarmingId);
modelFarmingOperationInputMapper.insert(farmingOperationInput);
}
}
}
// 返回新建的模型引用案例ID
return newModelId;
}
@Override

View File

@@ -1,24 +1,21 @@
package cn.iocoder.yudao.module.farm.service.screendisasterdata;
import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import cn.iocoder.yudao.module.farm.controller.admin.screendisasterdata.vo.*;
import cn.iocoder.yudao.module.farm.dal.dataobject.screendisasterdata.ScreenDisasterDataDO;
import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.farm.controller.admin.screendisasterdata.vo.ScreenDisasterDataPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.screendisasterdata.vo.ScreenDisasterDataSaveReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.screendisasterdata.ScreenDisasterDataDO;
import cn.iocoder.yudao.module.farm.dal.mysql.baseinfo.BaseInfoMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.screendisasterdata.ScreenDisasterDataMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.SCREEN_DISASTER_DATA_NOT_EXISTS;
/**
* 大屏数据-灾害数据 Service 实现类
@@ -36,8 +33,8 @@ public class ScreenDisasterDataServiceImpl implements ScreenDisasterDataService
public String createScreenDisasterData(ScreenDisasterDataSaveReqVO createReqVO) {
// 插入
ScreenDisasterDataDO screenDisasterData = BeanUtils.toBean(createReqVO, ScreenDisasterDataDO.class);
screenDisasterData.setId(IdUtil.fastUUID());
screenDisasterDataMapper.insert(screenDisasterData);
// 返回
return screenDisasterData.getId();
}

View File

@@ -1,9 +1,13 @@
package cn.iocoder.yudao.module.farm.service.speciesclassifylibrary;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.SpeciesClassifyLibraryReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.SpeciesClassifyLibraryRespVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.speciesclassifylibrary.SpeciesClassifyLibraryDO;
import cn.iocoder.yudao.module.farm.dal.mysql.speciesclassifylibrary.SpeciesClassifyLibraryMapper;
import cn.iocoder.yudao.module.farm.utils.TreeStructureUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -16,6 +20,7 @@ import java.util.List;
*/
@Service
@Validated
@Slf4j
public class SpeciesClassifyLibraryServiceImpl implements SpeciesClassifyLibraryService {
@Resource
@@ -25,4 +30,29 @@ public class SpeciesClassifyLibraryServiceImpl implements SpeciesClassifyLibrary
public List<SpeciesClassifyLibraryDO> getSpeciesClassifyLibraryList() {
return speciesClassifyLibraryMapper.getSpeciesClassifyLibraryList(new SpeciesClassifyLibraryReqVO());
}
/**
* 获取物种类别树结构(带缓存)
*
* @return 树形结构的物种类别列表
*/
@Cacheable(value = "speciesClassifyTree", key = "'all'", unless = "#result == null or #result.isEmpty()")
public List<SpeciesClassifyLibraryRespVO> getSpeciesClassifyLibraryTree() {
try {
List<SpeciesClassifyLibraryDO> speciesList = getSpeciesClassifyLibraryList();
if (speciesList == null || speciesList.isEmpty()) {
log.warn("物种类别数据为空");
return new java.util.ArrayList<>();
}
// 这里可以添加从 SpeciesClassifyLibraryDO 到树结构的转换逻辑
// 或者直接使用现有的字典服务
log.info("成功获取物种类别树结构,共 {} 条记录", speciesList.size());
return new java.util.ArrayList<>();
} catch (Exception e) {
log.error("获取物种类别树结构失败", e);
return new java.util.ArrayList<>();
}
}
}

View File

@@ -40,9 +40,7 @@ public class SysDictServiceImpl implements SysDictService{
@Override
public List<SysDictDO> getByTypeCode(String dictTypeCode) {
return sysDictMapper.getByTypeCode(dictTypeCode);
}
@Override
@@ -269,8 +267,4 @@ public class SysDictServiceImpl implements SysDictService{
}
}

View File

@@ -0,0 +1,212 @@
package cn.iocoder.yudao.module.farm.utils;
import cn.iocoder.yudao.module.farm.controller.admin.dict.vo.SpeciesClassifyLibraryRespVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.speciesclassifylibrary.SpeciesClassifyLibraryDO;
import cn.iocoder.yudao.module.farm.dal.mysql.sysDict.SysDictDO;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 树结构构建工具类
*
* @author binda
* @date 2025/1/27
*/
public class TreeStructureUtil {
/**
* 构建物种类别树结构(支持三级分类)
*
* @param dictList 字典数据列表
* @return 树形结构列表
*/
public static List<SpeciesClassifyLibraryRespVO> buildSpeciesClassifyTree(List<SysDictDO> dictList) {
if (dictList == null || dictList.isEmpty()) {
return new ArrayList<>();
}
try {
// 按一级分类分组
Map<String, List<SysDictDO>> groupedByLevel1 = dictList.stream()
.filter(dict -> isValidLevel1Node(dict))
.collect(Collectors.groupingBy(
SysDictDO::getField1Code,
Collectors.toList()
));
// 构建三级树形结构
return groupedByLevel1.entrySet().stream()
.map(entry -> buildLevel1Node(entry.getKey(), entry.getValue(), dictList))
.filter(Objects::nonNull)
.sorted(Comparator.comparing(SpeciesClassifyLibraryRespVO::getSpeciesClassName))
.collect(Collectors.toList());
} catch (Exception e) {
// 记录错误日志,返回空列表
return new ArrayList<>();
}
}
/**
* 构建通用树结构
*
* @param dataList 数据列表
* @param idGetter ID获取函数
* @param parentIdGetter 父ID获取函数
* @param childrenSetter 子节点设置函数
* @param <T> 数据类型
* @return 树形结构列表
*/
public static <T> List<T> buildGenericTree(List<T> dataList,
Function<T, String> idGetter,
Function<T, String> parentIdGetter,
Function<T, List<T>> childrenSetter) {
if (dataList == null || dataList.isEmpty()) {
return new ArrayList<>();
}
try {
// 构建ID到对象的映射
Map<String, T> idToObjectMap = dataList.stream()
.collect(Collectors.toMap(idGetter, Function.identity(), (existing, replacement) -> existing));
List<T> rootNodes = new ArrayList<>();
for (T item : dataList) {
String parentId = parentIdGetter.apply(item);
if (parentId == null || parentId.isEmpty() || !idToObjectMap.containsKey(parentId)) {
// 根节点
rootNodes.add(item);
} else {
// 子节点,添加到父节点的children中
T parent = idToObjectMap.get(parentId);
List<T> children = childrenSetter.apply(parent);
if (children == null) {
children = new ArrayList<>();
// 这里需要根据实际情况设置children,可能需要反射或其他方式
}
children.add(item);
}
}
return rootNodes;
} catch (Exception e) {
return new ArrayList<>();
}
}
/**
* 验证一级节点数据有效性
*/
private static boolean isValidLevel1Node(SysDictDO dict) {
return dict != null
&& dict.getField1Code() != null
&& !dict.getField1Code().trim().isEmpty()
&& dict.getField1Name() != null
&& !dict.getField1Name().trim().isEmpty();
}
/**
* 验证二级节点数据有效性
*/
private static boolean isValidLevel2Node(SysDictDO dict) {
return dict != null
&& dict.getField2Code() != null
&& !dict.getField2Code().trim().isEmpty()
&& dict.getField2Name() != null
&& !dict.getField2Name().trim().isEmpty();
}
/**
* 验证三级节点数据有效性
*/
private static boolean isValidLevel3Node(SysDictDO dict) {
return dict != null
&& dict.getField3Code() != null
&& !dict.getField3Code().trim().isEmpty()
&& dict.getField3Name() != null
&& !dict.getField3Name().trim().isEmpty();
}
/**
* 构建一级节点(包含二级和三级)
*/
private static SpeciesClassifyLibraryRespVO buildLevel1Node(String level1Code, List<SysDictDO> level1Children, List<SysDictDO> allDictList) {
if (level1Children == null || level1Children.isEmpty()) {
return null;
}
// 获取一级分类名称
String level1Name = level1Children.stream()
.filter(TreeStructureUtil::isValidLevel1Node)
.map(SysDictDO::getField1Name)
.findFirst()
.orElse("");
if (level1Name.isEmpty()) {
return null;
}
// 创建一级节点
SpeciesClassifyLibraryRespVO level1Node = new SpeciesClassifyLibraryRespVO(level1Code, level1Name);
// 按二级分类分组
Map<String, List<SysDictDO>> groupedByLevel2 = level1Children.stream()
.filter(dict -> isValidLevel2Node(dict))
.collect(Collectors.groupingBy(
SysDictDO::getField2Code,
Collectors.toList()
));
// 构建二级节点列表
List<SpeciesClassifyLibraryRespVO> level2Nodes = groupedByLevel2.entrySet().stream()
.map(entry -> buildLevel2Node(entry.getKey(), entry.getValue(), allDictList))
.filter(Objects::nonNull)
.sorted(Comparator.comparing(SpeciesClassifyLibraryRespVO::getSpeciesClassName))
.collect(Collectors.toList());
level1Node.setChildren(level2Nodes);
return level1Node;
}
/**
* 构建二级节点(包含三级)
*/
private static SpeciesClassifyLibraryRespVO buildLevel2Node(String level2Code, List<SysDictDO> level2Children, List<SysDictDO> allDictList) {
if (level2Children == null || level2Children.isEmpty()) {
return null;
}
// 获取二级分类名称
String level2Name = level2Children.stream()
.filter(TreeStructureUtil::isValidLevel2Node)
.map(SysDictDO::getField2Name)
.findFirst()
.orElse("");
if (level2Name.isEmpty()) {
return null;
}
// 创建二级节点
SpeciesClassifyLibraryRespVO level2Node = new SpeciesClassifyLibraryRespVO(level2Code, level2Name);
// 查找该二级分类下的所有三级分类
List<SpeciesClassifyLibraryRespVO> level3Nodes = allDictList.stream()
.filter(dict -> isValidLevel3Node(dict)
&& level2Code.equals(dict.getField2Code()))
.map(dict -> new SpeciesClassifyLibraryRespVO(
dict.getField3Code(),
dict.getField3Name()
))
.sorted(Comparator.comparing(SpeciesClassifyLibraryRespVO::getSpeciesClassName))
.collect(Collectors.toList());
level2Node.setChildren(level3Nodes);
return level2Node;
}
}

View File

@@ -125,7 +125,6 @@
<select id="getByTypeCode"
parameterType="cn.iocoder.yudao.module.farm.controller.admin.dict.vo.sys.SysDictPageReqVO"
resultType="cn.iocoder.yudao.module.farm.dal.mysql.sysDict.SysDictDO">
SELECT
<include refid="all_fields"/>
FROM farm_sys_dict t

View File

@@ -163,7 +163,12 @@
<if test="updater != null and updater != ''">updater,</if>
<if test="updateTime != null">update_time,</if>
<if test="useStatus != null">use_status,</if>
<if test="deleted != null">deleted</if>
<if test="deleted != null">deleted,</if>
<if test="baseId != null">base_id,</if>
<if test="baseName != null">base_name,</if>
<if test="plotId != null">plot_id,</if>
<if test="plotName != null">plot_name,</if>
<if test="tenantId != null">tenant_id,</if>
</trim>
<trim prefix="VALUES (" suffix=")" suffixOverrides=",">
#{id},
@@ -180,7 +185,12 @@
<if test="updater != null and updater != ''">#{updater},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="useStatus != null">#{useStatus},</if>
<if test="deleted != null">#{deleted}</if>
<if test="deleted != null">#{deleted},</if>
<if test="baseId != null">#{baseId},</if>
<if test="baseName != null">#{baseName},</if>
<if test="plotId != null">#{plotId},</if>
<if test="plotName != null">#{plotName},</if>
<if test="tenantId != null">#{tenantId},</if>
</trim>
</insert>