fix (farm): 集成测试,修复bug

- 生产计划
- 模型管理
- 基地管理
This commit is contained in:
达富斌
2025-09-10 18:14:10 +08:00
parent a71f0820d2
commit 90d3978771
12 changed files with 174 additions and 45 deletions

View File

@@ -12,15 +12,25 @@ import cn.iocoder.yudao.module.farm.dal.dataobject.farmingrecord.FarmingRecordDO
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.service.cropFarmingCenter.CropFarmingCenterService;
import cn.iocoder.yudao.module.farm.service.farmingrecord.FarmingRecordService;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*;
/**
* @description: 种植中心
@@ -55,10 +65,54 @@ public class CropFarmingCenterController {
// }
// 生产计划
// @GetMapping("/production-plan/page")
// @Operation(summary = "生产计划-分页")
// public CommonResult<PageResult<ProductionPlanResp2VO>> getProductionPlanPage(@Valid ProductionPlanPage2ReqVO pageReqVO) {
// return success(cropFarmingCenterService.getProductionPlanPage2(pageReqVO));
// }
@GetMapping("/production-plan/page")
@Operation(summary = "生产计划-分页")
public CommonResult<PageResult<ProductionPlanResp2VO>> getProductionPlanPage(@Valid ProductionPlanPage2ReqVO pageReqVO) {
return success(cropFarmingCenterService.getProductionPlanPage2(pageReqVO));
public TemResult getProductionPlanPage(@Valid ProductionPlanPage2ReqVO pageReqVO) {
PageResult<ProductionPlanResp2VO> page = cropFarmingCenterService.getProductionPlanPage2(pageReqVO);
List<ProductionPlanResp2VO> list = page.getList();
LocalDate minDate = list.stream()
.map(ProductionPlanResp2VO::getProductionStartDate)
.filter(Objects::nonNull)
.min(LocalDate::compareTo)
.orElse(null);
LocalDate maxDate = list.stream()
.map(ProductionPlanResp2VO::getProductionEndDate)
.filter(Objects::nonNull)
.max(LocalDate::compareTo)
.orElse(null);
return new TemResult(0, "success", new TemPage(page.getTotal(),page.getList(),minDate,maxDate));
}
/**
* 前端需要 minData,maxDate 字段, 临时封装的对象
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TemResult{
private Integer code;
private String msg;
private TemPage data;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TemPage{
@Schema(description = "总量", requiredMode = Schema.RequiredMode.REQUIRED)
private Long total;
@Schema(description = "数据", requiredMode = Schema.RequiredMode.REQUIRED)
private List<ProductionPlanResp2VO> list;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate minDate;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate maxDate;
}
@GetMapping("/production-plan/get/{id}")
@@ -107,7 +161,6 @@ public class CropFarmingCenterController {
double totalArea = res.getTotalArea();
double predictedArea = res.getPredictedArea();
double usagePercentage = (predictedArea / totalArea) * 100;
// String result = String.format("%.1f%%", percentage);
updateReqVO.setTotalArea(totalArea);
updateReqVO.setPredictedArea(predictedArea);

View File

@@ -23,9 +23,12 @@ public class ProductionPlanPage2ReqVO extends PageParam {
@Schema(description = "地块ID", example = "19246")
private String plotId;
@Schema(description = "排产日期")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDate[] productionStartDate;
// @Schema(description = "排产日期")
// @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
// private LocalDate[] productionStartDate;
@Schema(description = "排产日期-年份")
private String productionYear;
@Schema(description = "计划执行状态")
private Integer planStatus;

View File

@@ -8,6 +8,7 @@ import lombok.NoArgsConstructor;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
/**
* @description: 针对于前端甘特图的响应实体
@@ -74,7 +75,7 @@ public class ProductionPlanResp2VO {
@Schema(description = "模型名称")
private String modelName;
@Schema(description = "物种图片")
private String speciesImage;
private List<String> speciesImage;
@Schema(description = "种植物种-名称")
private String plantSpeciesName;
@Schema(description = "计划编号")
@@ -87,10 +88,10 @@ public class ProductionPlanResp2VO {
private Integer planSubStatus;
@Schema(description = "计划执行子状态-名称")
private String planSubStatusName;
@Schema(description = "生命周期-名称")
private String cycleName;
@Schema(description = "管理周期-名称")
private String managementCycleName;
@Schema(description = "种植面积")
private Double predictedArea;
private Integer predictedArea;
@Schema(description = "预计产量")
private Integer predictedYields;
@Schema(description = "任务进度",example = "1/10")

View File

@@ -55,7 +55,8 @@ public class ProductionPlanRespVO {
private String planSubStatusName;
@Schema(description = "逾期天数")
private Integer overdueDays;
@Schema(description = "地块负责人")
private String plotManger;
@Schema(description = "租户ID")
private String tenantId;

View File

@@ -133,13 +133,11 @@ public class ModelManagementController {
}
@GetMapping("/get/species")
@Operation(summary = "获得模型管理")
@Operation(summary = "获得模型与物种集合")
@Parameter(name = "speciesId", description = "物种编号", required = true, example = "1024")
public CommonResult<List<ModelManagementForPlanRespVO>> getModelManagementForPlan(@RequestParam String speciesId) {
return success(null);
List<ModelManagementForPlanRespVO> res = modelManagementService.getModelManagementForPlan(speciesId);
return success(res);
}
/**

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@@ -14,7 +15,13 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
public class ModelManagementForPlanRespVO {
private String xx;
@Schema(description = "物种ID")
private String speciesId;
@Schema(description = "模型名称")
private String modelName;
@Schema(description = "预计亩产")
private String harvest;
@Schema(description = "周期持续天数")
private Integer cycleDurationDays;
}

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.farm.dal.mysql.productionplan;
import cn.idev.excel.util.StringUtils;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
@@ -12,6 +13,7 @@ import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
import java.util.List;
/**
@@ -40,17 +42,30 @@ public interface ProductionPlanMapper extends BaseMapperX<ProductionPlanDO> {
}
default PageResult<ProductionPlanDO> selectPage2(ProductionPlanPage2ReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ProductionPlanDO>()
.betweenIfPresent(ProductionPlanDO::getProductionStartDate,
reqVO.getProductionStartDate() != null ? reqVO.getProductionStartDate()[0] : null,
reqVO.getProductionStartDate() != null ? reqVO.getProductionStartDate()[1] : null
)
LambdaQueryWrapperX<ProductionPlanDO> wrapperX = new LambdaQueryWrapperX<ProductionPlanDO>()
// .betweenIfPresent(ProductionPlanDO::getProductionStartDate,
// reqVO.getProductionStartDate() != null ? reqVO.getProductionStartDate()[0] : null,
// reqVO.getProductionStartDate() != null ? reqVO.getProductionStartDate()[1] : null
// )
.eqIfPresent(ProductionPlanDO::getBaseId, reqVO.getBaseId())
.eqIfPresent(ProductionPlanDO::getPlotId, reqVO.getPlotId())
.eqIfPresent(ProductionPlanDO::getPlanStatus, reqVO.getPlanStatus())
.eqIfPresent(ProductionPlanDO::getTenantId, reqVO.getTenantId())
.orderByDesc(ProductionPlanDO::getCreateTime)
);
.orderByDesc(ProductionPlanDO::getCreateTime);
if (StringUtils.isNotBlank(reqVO.getProductionYear())) {
try {
int year = Integer.parseInt(reqVO.getProductionYear());
// 构建该年份的开始和结束日期
LocalDate startDate = LocalDate.of(year, 1, 1);
LocalDate endDate = LocalDate.of(year, 12, 31);
wrapperX.between(ProductionPlanDO::getProductionStartDate, startDate, endDate);
} catch (NumberFormatException e) {
// 处理格式错误
throw new IllegalArgumentException("productionYear格式错误,应为yyyy格式");
}
}
return selectPage(reqVO, wrapperX);
}
default PageResult<ProductionPlanDO> selectPage3(FarmProductionPlanReqVO reqVO) {

View File

@@ -118,7 +118,8 @@ public interface ErrorCodeConstants {
ErrorCode TWO_DICT_NOT_EXISTS = new ErrorCode(1_050_035_000, "字典不存在");
ErrorCode PLOT_AREA_ERRORS = new ErrorCode(1_050_036_000, "地块面积总和大于基地面积");
ErrorCode PLOT_AREA_EXISTS_ERRORS = new ErrorCode(1_050_036_001, "该基地下存在地块,不可删除");
ErrorCode PLOT_AREA_EXISTS_ERRORS = new ErrorCode(1_050_036_001, "该基地存在地块,不可删除");
ErrorCode BEING_PLOT_AREA_EXISTS_ERRORS = new ErrorCode(1_050_036_002, "该基地存在在种地块,不可删除");
ErrorCode INDICATOR_NAME_NOT_EXISTS = new ErrorCode(1_050_037_000, "指标名称不存在");

View File

@@ -46,8 +46,7 @@ import java.util.stream.Collectors;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.BASE_INFO_NOT_EXISTS;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PLOT_AREA_EXISTS_ERRORS;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.*;
/**
* 基地 Service 实现类
@@ -103,8 +102,6 @@ public class BaseInfoServiceImpl implements BaseInfoService {
// 更新
BaseInfoDO updateObj = BeanUtils.toBean(updateReqVO, BaseInfoDO.class);
baseInfoMapper.updateById(updateObj);
// 同步
// productionPlanService.syncBaseAreaToAllPlansByBaseId(baseId, newArea, oldArea);
}
@Override
@@ -113,14 +110,16 @@ public class BaseInfoServiceImpl implements BaseInfoService {
validateBaseInfoExists(id);
// 校验: 存在在种地块时 不允许删除
boolean flag = productionPlanService.validateIncompletePlansBId("base_id", id);
if (!flag) {
throw exception(BEING_PLOT_AREA_EXISTS_ERRORS);
}
boolean flag2 = plotInfoService.validatePlotExistByBaseId(id);
if (flag || flag2) {
if (!flag2) {
throw exception(PLOT_AREA_EXISTS_ERRORS);
}
// 删除
baseInfoMapper.deleteById(id);
plotInfoService.deleteByBaseId(id);
}else {
throw exception(PLOT_AREA_EXISTS_ERRORS);
}
}
@Override

View File

@@ -26,6 +26,7 @@ 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.plotinfo.PlotInfoService;
import cn.iocoder.yudao.module.farm.utils.BigDecimalUtil;
import cn.iocoder.yudao.module.farm.utils.StrHelperUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
@@ -217,11 +218,15 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
if (productionPlanDO == null) {
throw exception(PRODUCTION_PLAN_NOT_EXISTS);
}
Map<String, String> employeeNameMap = personnelManagementMapper.selectList().stream().collect(toMap(PersonnelManagementDO::getId, PersonnelManagementDO::getName, (v1, v2) -> v1));
ModelManagementRespVO modelManagementRespVO = modelManagementService.getModelManagement(productionPlanDO.getSpeciesModelId());
ProductionPlanRespVO productionPlanRespVO = BeanUtils.toBean(productionPlanDO, ProductionPlanRespVO.class);
productionPlanRespVO.setModelManagementRespVO(modelManagementRespVO);
// 地块负责人
String plotId = productionPlanRespVO.getPlotId();
PlotInfoDO plotIObj = plotInfoService.getPlotInfoByPlotId(plotId);
productionPlanRespVO.setPlotManger(employeeNameMap.getOrDefault(plotIObj.getEmployeeId(),"系统"));
return productionPlanRespVO;
}
@@ -275,8 +280,10 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
public PageResult<ProductionPlanResp2VO> getProductionPlanPage2(ProductionPlanPage2ReqVO reqVO) {
Map<String, String> speciesNameMap = speciesLibraryMapper.selectList().stream().collect(toMap(SpeciesLibraryDO::getId, SpeciesLibraryDO::getCultivarName, (v1, v2) -> v1));
Map<String, String> employeeNameMap = personnelManagementMapper.selectList().stream().collect(toMap(PersonnelManagementDO::getId, PersonnelManagementDO::getName, (v1, v2) -> v1));
reqVO.setTenantId(getLoginUser().getTenantId().toString());
PageResult<ProductionPlanDO> productionPlanDOPageResult = productionPlanMapper.selectPage2(reqVO);
List<ProductionPlanDO> planList = productionPlanDOPageResult.getList();
Map<String, List<ProductionPlanDO>> plansByBaseName = planList.stream().collect(Collectors.groupingBy(ProductionPlanDO::getBaseName, toList()));
@@ -343,7 +350,7 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
BaseInfoDO baseObj = baseInfoMapper.selectOne("id", planObj.getBaseId());
if (baseObj != null) {
ProductionPlanRespVO.PlanOverview source = productionPlanMapper.getPlanOverview(planObj.getBaseId(), getLoginUser().getTenantId().toString());
source.setTotalArea(baseObj.getArea());
source.setTotalArea(BigDecimalUtil.roundedViaMath(baseObj.getArea()));
return BeanUtils.toBean(source, ProductionPlanResp2VO.PlanOverview.class);
} else {
return null;
@@ -355,21 +362,23 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
BaseInfoDO baseObj = baseInfoMapper.selectOne("id", planObj.getBaseId());
if (baseObj != null) {
String employeeId = baseObj.getManager();
ModelManagementDO modelManagementDo = modelManagementService.getModelManagement("id", planObj.getSpeciesModelId());
String managementCycleName = "";
ProductionPlanResp2VO.ModelInfo modelInfo = new ProductionPlanResp2VO.ModelInfo();
modelInfo.setId(modelManagementDo.getId());
modelInfo.setModelName(modelManagementDo.getModelName());
modelInfo.setSpeciesImage(modelManagementDo.getSpeciesImage());
modelInfo.setSpeciesImage(modelManagementDo.getSpeciesImageList());
modelInfo.setPlantSpeciesName(modelManagementDo.getSpeciesName());
modelInfo.setPlanNumber(planObj.getPlanNumber());
modelInfo.setPlanStatus(planObj.getPlanStatus());
modelInfo.setPlanSubStatus(ObjectUtils.defaultIfNull(planObj.getPlanSubStatus(), planObj.getPlanStatus()));
modelInfo.setPlanStatusName(PLAN_MAP.getOrDefault(planObj.getPlanStatus(), ""));
modelInfo.setPlanSubStatusName(PLAN_MAP.getOrDefault(planObj.getPlanSubStatus(), ""));
modelInfo.setCycleName(modelManagementDo.getCycleName());
modelInfo.setPredictedArea(planObj.getPredictedArea());
modelInfo.setManagementCycleName(managementCycleName);
modelInfo.setPredictedArea(planObj.getPredictedArea().intValue());
modelInfo.setPredictedYields(planObj.getPredictedYields());
modelInfo.setProgressBar("1/10"); // TODO: 2025/8/30 农事记录
modelInfo.setProgressRatio("10"); // TODO: 2025/8/31
@@ -509,7 +518,7 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
}
ProductionPlanRespVO.PlanOverview source = productionPlanMapper.getPlanOverview(baseId, tenantId.toString());
return new BasePlanOverviewRespVO().setTotalArea(totalArea)
return new BasePlanOverviewRespVO().setTotalArea(BigDecimalUtil.roundedViaMath(totalArea))
.setPlanCount(source.getPlanCount())
.setPlanCompletedCount(source.getPlanCompletedCount())
.setPlanInProgressCount(source.getPlanInProgressCount())
@@ -524,6 +533,6 @@ public class CropFarmingCenterServiceImpl implements CropFarmingCenterService {
BigDecimal totalArea = baseInfoMapper.getTotalBaseArea(baseId, tenantId);
int farmRecordCount = farmingRecordService.getFarmRecordOverview(baseId);
return new FarmRecordOverviewRespVO(totalArea, farmRecordCount);
return new FarmRecordOverviewRespVO(BigDecimalUtil.roundedViaMath(totalArea), farmRecordCount);
}
}

View File

@@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.farm.service.modelmanagement;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementForPlanRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementSaveReqVO;
@@ -89,4 +90,10 @@ public interface ModelManagementService {
*/
Map<String, List<ModelFarmingOperationDO>> getRecordList(List<String> taskIdList);
/**
* 通过物种ID 获取 模型管理信息
* @param speciesId
* @return
*/
List<ModelManagementForPlanRespVO> getModelManagementForPlan(String speciesId);
}

View File

@@ -4,9 +4,12 @@ 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.dict.core.DictFrameworkUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.farm.controller.admin.modelcycle.vo.ModelCycleRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelfarmingoperation.vo.ModelFarmingOperationRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementForPlanRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.modelmanagement.vo.ModelManagementSaveReqVO;
@@ -94,7 +97,6 @@ public class ModelManagementServiceImpl implements ModelManagementService {
modelManagement.setSpeciesName(speciesLibrary.getSpeciesName() + "/" + speciesLibrary.getCultivarName());
modelManagement.setCycle(speciesLibrary.getLifeCycle().toString());
modelManagement.setCycleName(LIFE_CYCLE_MAP.getOrDefault(speciesLibrary.getLifeCycle().toString(),""));
modelManagement.setSpeciesImage(speciesLibrary.getImage());
// 处理suitablePlantingAreas字段,优先使用集合
if (createReqVO.getSuitablePlantingAreas() != null && !createReqVO.getSuitablePlantingAreas().isEmpty()) {
modelManagement.setSuitablePlantingAreasList(createReqVO.getSuitablePlantingAreas());
@@ -106,7 +108,7 @@ public class ModelManagementServiceImpl implements ModelManagementService {
} else if (createReqVO.getSpeciesImage() != null) {
modelManagement.setSpeciesImageList(libraryDO.getImageList());
}
modelManagement.setSpeciesImage(libraryDO.getImage());
modelManagementMapper.insert(modelManagement);
// 返回
@@ -487,4 +489,37 @@ public class ModelManagementServiceImpl implements ModelManagementService {
return resMap;
}
@Override
public List<ModelManagementForPlanRespVO> getModelManagementForPlan(String speciesId) {
LambdaQueryWrapperX<ModelManagementDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.eq(ModelManagementDO::getSpeciesId, speciesId);
wrapperX.eq(ModelManagementDO::getIsRelease, YES_CODE); // 发布状态
wrapperX.eq(ModelManagementDO::getType, MODEL_TYPE_1); // 模版类型
wrapperX.eq(ModelManagementDO::getTenantId, getLoginUser().getTenantId());
List<ModelManagementDO> modelManagementDOS = modelManagementMapper.selectList(wrapperX);
List<ModelManagementForPlanRespVO> res = new ArrayList<>();
for (ModelManagementDO m : modelManagementDOS) {
String modelId = m.getId();
String modelName = m.getModelName();
String harvest = m.getHarvest();
List<ModelCycleDO> cycleDOS = getModelCycleListByModelId(modelId);
if (ObjectUtils.isEmpty(cycleDOS)) {
continue;
}
Integer sum = cycleDOS.stream().mapToInt(cycle -> cycle.getStage() != null ? cycle.getStage() : 0).sum();
res.add(new ModelManagementForPlanRespVO(modelId,modelName,harvest,sum));
}
return res;
}
private List<ModelCycleDO> getModelCycleListByModelId(String modelId) {
LambdaQueryWrapperX<ModelCycleDO> wrapperXx = new LambdaQueryWrapperX<>();
wrapperXx.eq(ModelCycleDO::getModelId, modelId);
wrapperXx.eq(ModelCycleDO::getTenantId, getLoginUser().getTenantId());
return modelCycleMapper.selectList(wrapperXx);
}
}