feat (farm): 基地,地块

- 新增,修改,删除时添加面积限制
This commit is contained in:
达富斌
2025-08-29 12:41:06 +08:00
parent 04f1ec8c80
commit 7464c7af87
5 changed files with 185 additions and 34 deletions

View File

@@ -117,4 +117,6 @@ public interface ErrorCodeConstants {
// ========== 设备报警 1_050_035_000 ========== // ========== 设备报警 1_050_035_000 ==========
ErrorCode TWO_DICT_NOT_EXISTS = new ErrorCode(1_050_035_000, "字典不存在"); ErrorCode TWO_DICT_NOT_EXISTS = new ErrorCode(1_050_035_000, "字典不存在");
ErrorCode PLOT_AREA_ERRORS = new ErrorCode(1_050_036_000, "地块面积总和大于基地面积");
} }

View File

@@ -13,9 +13,9 @@ import cn.iocoder.yudao.module.farm.dal.mysql.baseinfo.BaseInfoMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.gridinfo.GridInfoMapper; import cn.iocoder.yudao.module.farm.dal.mysql.gridinfo.GridInfoMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.PersonnelManagementMapper; import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.PersonnelManagementMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotInfoMapper; import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotInfoMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.productionplan.ProductionPlanMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.specieslibrary.SpeciesLibraryMapper; import cn.iocoder.yudao.module.farm.dal.mysql.specieslibrary.SpeciesLibraryMapper;
import cn.iocoder.yudao.module.farm.enums.CommonConstants; import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
@@ -48,14 +48,13 @@ public class BaseInfoServiceImpl implements BaseInfoService {
@Resource @Resource
private PlotInfoMapper plotInfoMapper; private PlotInfoMapper plotInfoMapper;
@Resource @Resource
private ProductionPlanMapper productionPlanMapper;
@Resource
private SpeciesLibraryMapper speciesLibraryMapper; private SpeciesLibraryMapper speciesLibraryMapper;
@Resource @Resource
private PersonnelManagementMapper personnelManagementMapper; private PersonnelManagementMapper personnelManagementMapper;
@Resource @Resource
private GridInfoMapper gridInfoMapper; private GridInfoMapper gridInfoMapper;
@Resource
private ProductionPlanService productionPlanService;
@Override @Override
public String createBaseInfo(BaseInfoSaveReqVO createReqVO) { public String createBaseInfo(BaseInfoSaveReqVO createReqVO) {
@@ -72,21 +71,32 @@ public class BaseInfoServiceImpl implements BaseInfoService {
@Override @Override
public void updateBaseInfo(BaseInfoSaveReqVO updateReqVO) { public void updateBaseInfo(BaseInfoSaveReqVO updateReqVO) {
String baseId = updateReqVO.getId();
// 校验存在 // 校验存在
validateBaseInfoExists(updateReqVO.getId()); validateBaseInfoExists(baseId);
BaseInfoDO sourceBaseInfoDO = baseInfoMapper.selectById(baseId);
BigDecimal oldArea = sourceBaseInfoDO.getArea();
BigDecimal newArea = updateReqVO.getArea();
// 更新 // 更新
BaseInfoDO updateObj = BeanUtils.toBean(updateReqVO, BaseInfoDO.class); BaseInfoDO updateObj = BeanUtils.toBean(updateReqVO, BaseInfoDO.class);
baseInfoMapper.updateById(updateObj); baseInfoMapper.updateById(updateObj);
// 同步
productionPlanService.syncBaseAreaToAllPlansByBaseId(baseId, newArea, oldArea);
} }
@Override @Override
public void deleteBaseInfo(String id) { public void deleteBaseInfo(String id) {
// 校验存在 // 校验存在
validateBaseInfoExists(id); validateBaseInfoExists(id);
// 校验: 存在在种地块时 不允许删除
boolean flag = productionPlanService.validateIncompletePlansBId("base_id",id);
if (flag) {
// 删除 // 删除
baseInfoMapper.deleteById(id); baseInfoMapper.deleteById(id);
} }
}
@Override @Override
public void deleteBaseInfoListByIds(List<String> ids) { public void deleteBaseInfoListByIds(List<String> ids) {
// 删除 // 删除
@@ -184,28 +194,37 @@ public class BaseInfoServiceImpl implements BaseInfoService {
} }
private void packageBaseInfo(long tenantId,List<BaseInfoRespVO> respVOS, Map<String, String> employeeMap) { private void packageBaseInfo(long tenantId,List<BaseInfoRespVO> respVOS, Map<String, String> employeeMap) {
for (BaseInfoRespVO obj : respVOS) { for (BaseInfoRespVO obj : respVOS) {
String baseId = obj.getId(); String baseId = obj.getId();
String baseName = obj.getName(); String baseName = obj.getName();
BigDecimal baseArea = obj.getArea(); BigDecimal baseArea = obj.getArea();
List<PlotInfoDO> plotList = plotInfoMapper.selectList("base_id", baseId); List<PlotInfoDO> plotList = plotInfoMapper.selectList("base_id", baseId);
// 基地概述
BaseInfoRespVO.BaseInfo baseOverview = this.packageBaseOverview(tenantId, baseId, baseName, baseArea, plotList);
obj.setBaseOverview(baseOverview);
// 地块集合
List<BaseInfoRespVO.PlotInfo> targetList = this.packagePlotInfo(employeeMap, plotList);
obj.setPlotOverviewList(targetList);
}
}
private BaseInfoRespVO.BaseInfo packageBaseOverview(long tenantId, String baseId, String baseName, BigDecimal baseArea, List<PlotInfoDO> plotList) {
// 在种作物数量 // 在种作物数量
Integer cropCount = speciesLibraryMapper.getSpeciesCount(tenantId, baseId); Integer cropCount = speciesLibraryMapper.getSpeciesCount(tenantId, baseId);
// 在种地块占比 // 在种地块占比
double plotRatio = 0.00; double plotRatio = 0.00;
// 在种地块数量 // 在种地块数量
int plotCount = 1; int plotCount = productionPlanService.getGrowingPlotCount(baseId);
// 地块总数 // 地块总数
int plotTotalCount = plotList.size(); int plotTotalCount = plotList.size();
if (plotTotalCount > 0) { if (plotTotalCount > 0) {
plotRatio = Math.round((plotCount * 10000.0) / plotTotalCount) / 100.0; plotRatio = Math.round((plotCount * 10000.0) / plotTotalCount) / 100.0;
} }
return new BaseInfoRespVO.BaseInfo(baseId, baseName, baseArea, cropCount, plotCount, plotTotalCount, plotRatio);
}
obj.setBaseOverview(new BaseInfoRespVO.BaseInfo(baseId,baseName,baseArea,cropCount,plotCount,plotTotalCount,plotRatio)); private List<BaseInfoRespVO.PlotInfo> packagePlotInfo(Map<String, String> employeeMap, List<PlotInfoDO> plotList) {
// 地块集合
List<BaseInfoRespVO.PlotInfo> targetList = new ArrayList<>(); List<BaseInfoRespVO.PlotInfo> targetList = new ArrayList<>();
for (PlotInfoDO aDo : plotList) { for (PlotInfoDO aDo : plotList) {
String plotManager = employeeMap.getOrDefault(aDo.getEmployeeId(), "系统"); String plotManager = employeeMap.getOrDefault(aDo.getEmployeeId(), "系统");
@@ -213,8 +232,7 @@ public class BaseInfoServiceImpl implements BaseInfoService {
BaseInfoRespVO.PlotInfo target = new BaseInfoRespVO.PlotInfo(aDo.getId(), aDo.getPlotName(), aDo.getPlotColor(), aDo.getPlotArea(), plotManager, aDo.getPoint(), gridInfos); BaseInfoRespVO.PlotInfo target = new BaseInfoRespVO.PlotInfo(aDo.getId(), aDo.getPlotName(), aDo.getPlotColor(), aDo.getPlotArea(), plotManager, aDo.getPoint(), gridInfos);
targetList.add(target); targetList.add(target);
} }
obj.setPlotOverviewList(targetList); return targetList;
}
} }
private List<BaseInfoRespVO.GridInfo> packageGridInfo(String plotId) { private List<BaseInfoRespVO.GridInfo> packageGridInfo(String plotId) {

View File

@@ -6,17 +6,23 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.farm.controller.admin.plotinfo.vo.PlotInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.plotinfo.vo.PlotInfoPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.plotinfo.vo.PlotInfoSaveReqVO; import cn.iocoder.yudao.module.farm.controller.admin.plotinfo.vo.PlotInfoSaveReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.plotinfo.PlotInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.plotinfo.PlotInfoDO;
import cn.iocoder.yudao.module.farm.dal.mysql.baseinfo.BaseInfoMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotInfoMapper; import cn.iocoder.yudao.module.farm.dal.mysql.plotinfo.PlotInfoMapper;
import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService;
import cn.iocoder.yudao.module.farm.utils.StrHelperUtil;
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.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PLOT_AREA_ERRORS;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PLOT_INFO_NOT_EXISTS; import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PLOT_INFO_NOT_EXISTS;
/** /**
@@ -28,15 +34,26 @@ import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PLOT_INFO_NO
@Validated @Validated
public class PlotInfoServiceImpl implements PlotInfoService { public class PlotInfoServiceImpl implements PlotInfoService {
@Resource
private BaseInfoMapper baseInfoMapper;
@Resource @Resource
private PlotInfoMapper plotInfoMapper; private PlotInfoMapper plotInfoMapper;
@Resource
private ProductionPlanService productionPlanService;
@Override @Override
public String createPlotInfo(PlotInfoSaveReqVO createReqVO) { public String createPlotInfo(PlotInfoSaveReqVO createReqVO) {
LoginUser user = getLoginUser(); LoginUser user = getLoginUser();
// 验证地块面积总和 需要小于或等于 基地面积
boolean flag = this.validateTotalPlotArea(createReqVO.getBaseId());
if (flag) {
throw exception(PLOT_AREA_ERRORS);
}
// 插入 // 插入
PlotInfoDO plotInfo = BeanUtils.toBean(createReqVO, PlotInfoDO.class); PlotInfoDO plotInfo = BeanUtils.toBean(createReqVO, PlotInfoDO.class);
plotInfo.setId(IdUtil.fastUUID()); plotInfo.setId(IdUtil.fastUUID());
plotInfo.setPlotId(StrHelperUtil.generate());
plotInfo.setTenantId(String.valueOf(user.getTenantId())); plotInfo.setTenantId(String.valueOf(user.getTenantId()));
plotInfoMapper.insert(plotInfo); plotInfoMapper.insert(plotInfo);
@@ -48,18 +65,32 @@ public class PlotInfoServiceImpl implements PlotInfoService {
public void updatePlotInfo(PlotInfoSaveReqVO updateReqVO) { public void updatePlotInfo(PlotInfoSaveReqVO updateReqVO) {
// 校验存在 // 校验存在
validatePlotInfoExists(updateReqVO.getId()); validatePlotInfoExists(updateReqVO.getId());
// PlotInfoDO sourcePlotInfoDO = plotInfoMapper.selectById(updateReqVO.getId());
// String plotId = sourcePlotInfoDO.getPlotId();
// BigDecimal oldArea = sourcePlotInfoDO.getPlotArea();
// BigDecimal newArea = updateReqVO.getPlotArea();
// 更新 // 更新
PlotInfoDO updateObj = BeanUtils.toBean(updateReqVO, PlotInfoDO.class); PlotInfoDO updateObj = BeanUtils.toBean(updateReqVO, PlotInfoDO.class);
plotInfoMapper.updateById(updateObj); plotInfoMapper.updateById(updateObj);
// 同步
// productionPlanService.syncPlotAreaToAllPlansByBaseId(plotId,newArea,oldArea);
} }
@Override @Override
public void deletePlotInfo(String id) { public void deletePlotInfo(String id) {
// 校验存在 // 校验存在
validatePlotInfoExists(id); PlotInfoDO obj = plotInfoMapper.selectById(id);
if (obj == null) {
throw exception(PLOT_INFO_NOT_EXISTS);
}
// 校验: 存在在种地块时 不允许删除
boolean flag = productionPlanService.validateIncompletePlansBId("plot_id",obj.getPlotId());
// 删除 // 删除
if (flag) {
plotInfoMapper.deleteById(id); plotInfoMapper.deleteById(id);
} }
}
@Override @Override
public void deletePlotInfoListByIds(List<String> ids) { public void deletePlotInfoListByIds(List<String> ids) {
@@ -100,4 +131,25 @@ public class PlotInfoServiceImpl implements PlotInfoService {
return plotInfoMapper.selectOne(queryWrapper); return plotInfoMapper.selectOne(queryWrapper);
} }
/**
* 验证: 地块总面积不得大于基地面积
* @param baseId 基地面积
*/
private boolean validateTotalPlotArea(String baseId){
BaseInfoDO baseObj = baseInfoMapper.selectOne("id", baseId);
BigDecimal baseArea = baseObj.getArea();
List<PlotInfoDO> plotInfoDOS = plotInfoMapper.selectList("base_id", baseId);
if (plotInfoDOS == null || plotInfoDOS.isEmpty()) {
return true;
}
BigDecimal plotTotalArea = plotInfoDOS.stream()
.map(PlotInfoDO::getPlotArea)
.filter(area -> area != null) // 重要:过滤null值
.reduce(BigDecimal.ZERO, BigDecimal::add);
return plotTotalArea.compareTo(baseArea) > 0 ;
}
} }

View File

@@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.farm.dal.dataobject.productionplan.ProductionPlan
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
/** /**
@@ -74,4 +75,40 @@ public interface ProductionPlanService {
*/ */
List<BaseNamePlanRespVO> getBaseNameAndPlanList(); List<BaseNamePlanRespVO> getBaseNameAndPlanList();
/**
* 用于: 修改基地面积
* 1. 基地面积不可以小于地块面积总和.
* 2. 基地面积不同步到每个关联生产计划中.
*
* @param baseId 基地编号
* @param newArea 更新后的基地面积
* @param oldArea 更新前的基地面积
*/
void syncBaseAreaToAllPlansByBaseId(String baseId, BigDecimal newArea, BigDecimal oldArea);
/**
* 用于: 修改地块面积
* 1. 地块总面积不可大于基地面积 且 不可小于在种地块面积之和
* 2. 基地面积不同步到每个关联生产计划中.
*
* @param plotId 地块编号 ,不是ID
* @param newArea 新地块面积
* @param oldArea 旧地块面积
*/
void syncPlotAreaToAllPlansByBaseId(String plotId, BigDecimal newArea, BigDecimal oldArea);
/**
* 用于: 删除基地
* 需要先验证改基地下属地块是否关联未完成的计划. 存在则不可删除.
*
* @param baseId 基地ID
*/
boolean validateIncompletePlansBId(String field, String baseId);
/**
* 获取在种地块数量
* @param baseId
* @return
*/
int getGrowingPlotCount(String baseId);
} }

View File

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseNamePlanRes
import cn.iocoder.yudao.module.farm.controller.admin.productionplan.vo.ProductionPlanPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.productionplan.vo.ProductionPlanPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.productionplan.vo.ProductionPlanSaveReqVO; import cn.iocoder.yudao.module.farm.controller.admin.productionplan.vo.ProductionPlanSaveReqVO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -19,13 +20,13 @@ import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.farm.dal.mysql.productionplan.ProductionPlanMapper; import cn.iocoder.yudao.module.farm.dal.mysql.productionplan.ProductionPlanMapper;
import java.util.ArrayList; import java.math.BigDecimal;
import java.util.List; import java.util.*;
import java.util.Map;
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;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
import static cn.iocoder.yudao.module.farm.enums.CommonConstants.*;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PRODUCTION_PLAN_NOT_EXISTS; import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.PRODUCTION_PLAN_NOT_EXISTS;
/** /**
@@ -156,4 +157,45 @@ public class ProductionPlanServiceImpl implements ProductionPlanService {
} }
@Override
public void syncBaseAreaToAllPlansByBaseId(String baseId, BigDecimal newArea, BigDecimal oldArea) {
if (oldArea.compareTo(newArea) == 0) {
return ;
}
List<ProductionPlanDO> planList = productionPlanMapper.selectList("base_id", baseId);
planList.forEach(e -> e.setTotalArea(newArea.doubleValue()));
productionPlanMapper.updateBatch(planList);
}
@Override
public void syncPlotAreaToAllPlansByBaseId(String plotId, BigDecimal newArea, BigDecimal oldArea) {
// if (oldArea.compareTo(newArea) == 0) {
// return ;
// }
// List<ProductionPlanDO> planList = productionPlanMapper.selectList("plot_id", plotId);
}
@Override
public boolean validateIncompletePlansBId(String field,String baseId) {
List<ProductionPlanDO> planList = productionPlanMapper.selectList(field, baseId);
Set<Integer> planStatusSet = planList.stream()
.filter(e -> !ObjectUtils.notEqual(e.getPlanStatus(), PLAN_STATUS_3))
.map(ProductionPlanDO::getPlanStatus)
.collect(Collectors.toSet());
// 存在未完成状态的计划 不可删除
if (planStatusSet.size() > 0) {
return false;
}
return false;
}
@Override
public int getGrowingPlotCount(String baseId) {
List<ProductionPlanDO> planList = productionPlanMapper.selectList("base_id", baseId);
long count = planList.stream().filter(e -> Objects.equals(e.getPlanStatus(), PLAN_STATUS_2)).count();
return (int) count;
}
} }