feat (farm): 远程API

- 生产计划-分页
- 生产计划-详情
- 数字驾驶舱-基地概要信息
- 数字驾驶舱-基地信息列表
- 数字驾驶舱-生产数据-产量对比
- 数字驾驶舱-生产数据-种植计划完成情况
This commit is contained in:
达富斌
2025-09-04 21:34:14 +08:00
parent 84caa2ac63
commit 7133391cdd
28 changed files with 764 additions and 9 deletions

View File

@@ -0,0 +1,90 @@
package cn.iocoder.yudao.module.farm.controller.admin.api;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.service.baseinfo.BaseInfoService;
import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @description: api 接口
* @author: binda
* @date: 2025/9/2 19:33
*/
@Tag(name = "API接口")
@RestController
@RequestMapping("/farm/remote")
@Validated
public class ApiController {
private final ProductionPlanService productionPlanService;
private final BaseInfoService baseInfoService;
public ApiController(ProductionPlanService productionPlanService, BaseInfoService baseInfoService) {
this.productionPlanService = productionPlanService;
this.baseInfoService = baseInfoService;
}
/**
* 生产计划-分页查询
*
* 根据租户id、开始时间、结束时间,查询已完成的种植计划列表,返参:种植计划id、种植计划名称
*
* @param req 根据租户id、开始时间、结束时间 ,已完成状态
* @return 种植计划id、种植计划名称
*/
@GetMapping("/production-plan/page")
@Operation(summary = "生产计划-分页")
public CommonResult<PageResult<FarmProductionPlanRespVO>> getPageForFarmProductionPlan(@Valid @RequestBody FarmProductionPlanReqVO req) {
return productionPlanService.getPageForFarmProductionPlan(req);
}
/**
* 生产计划-详情查询
*
* 根据租户id、种植计划id,查询种植计划详情,返参:种植计划id、种植计划名称、种植开始时间、种植结束时间、计划所属的基地图片、基地简介、基地中心坐标点
*
* @param req 根据租户id、种植计划id
* @return 种植计划id、种植计划名称、种植开始时间、种植结束时间、计划所属的基地图片、基地简介、基地中心坐标点
*/
@GetMapping("/production-plan/get")
@Operation(summary = "生产计划-详情")
public CommonResult<FarmProductionPlanDetailRespVO> getDetailForFarmProductionPlan(@Valid @RequestBody FarmProductionPlanDetailReqVO req) {
return productionPlanService.getDetailForFarmProductionPlan(req);
}
@GetMapping("/digital-cockpit/get")
@Operation(summary = "数字驾驶舱-基地概要信息")
public CommonResult<FarmBaseOverviewRespVO> getBaseOverview(@Valid @RequestBody FarmBaseOverviewReqVO req) {
return baseInfoService.getBaseOverview(req);
}
@GetMapping("/digital-cockpit/list")
@Operation(summary = "数字驾驶舱-基地信息列表")
public CommonResult<List<FarmBaseInfoRespVO>> getBaseInfoList(@Valid @RequestBody FarmBaseInfoReqVO req) {
return baseInfoService.getBaseInfoList(req);
}
@GetMapping("/digital-cockpit/chart/yield-comparison")
@Operation(summary = "数字驾驶舱-生产数据-产量对比")
public CommonResult<List<YieldComparisonChartRespVO>> getYieldComparisonChart(@Valid @RequestBody YieldComparisonChartReqVO req) {
return productionPlanService.getYieldComparisonChart(req);
}
@GetMapping("/digital-cockpit/chart/planting-plan-completion")
@Operation(summary = "数字驾驶舱-生产数据-种植计划完成情况")
public CommonResult<List<PlantingPlanCompletionRespVO>> getPlantingPlanCompletionChart(@Valid @RequestBody PlantingPlanCompletionReqVO req) {
return productionPlanService.getPlantingPlanCompletionChart(req);
}
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-基地信息列表-请求实体
* @author: binda
* @date: 2025/9/4 19:14
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmBaseInfoReqVO {
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,25 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-基地信息列表-响应实体
* @author: binda
* @date: 2025/9/4 19:14
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmBaseInfoRespVO {
@Schema(description = "基地ID")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "基地范围坐标")
private String basePoint;
@Schema(description = "基地中心坐标")
private String baseCentrePoint;
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-基地概要信息-请求实体
* @author: binda
* @date: 2025/9/4 14:26
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmBaseOverviewReqVO {
@Schema(description = "基地D")
@NotNull(message = "基地D: 不能为空")
private String baseId;
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,63 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-基地概要信息-响应实体
* @author: binda
* @date: 2025/9/4 14:25
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmBaseOverviewRespVO {
private TenantInfo tenantInfo;
private BaseInfo baseInfo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class TenantInfo{
@Schema(description = "租户ID")
private String tenantId;
@Schema(description = "基地总面积")
private Double baseTotalArea;
@Schema(description = "基地总数量")
private Integer baseTotalCount;
@Schema(description = "品种总数量")
private Integer cropTotalCount;
@Schema(description = "物联网设备总数")
private Integer iotDeviceTotalCount;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class BaseInfo{
@Schema(description = "基地ID")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "基地名称")
private Double baseArea;
@Schema(description = "基地范围坐标")
private String basePoint;
@Schema(description = "基地中心坐标")
private String baseCentrePoint;
@Schema(description = "在种作物数量")
private Integer plantingCropCount;
@Schema(description = "在种地块数量")
private Integer plantingPlotCount;
@Schema(description = "物联网设备数量")
private Integer iotDeviceCount;
@Schema(description = "在种任务数量")
private Integer plantingTaskCount;
@Schema(description = "管理员姓名")
private String administratorName;
}
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 种植计划 详情 请求实体
* @author: binda
* @date: 2025/9/4 11:41
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmProductionPlanDetailReqVO {
@Schema(description = "生产计划ID")
@NotNull(message = "种植计划ID: 不能为空")
private String productionPlanId;
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
/**
* @description: 种植计划 详情 响应实体
* @author: binda
* @date: 2025/9/4 11:39
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmProductionPlanDetailRespVO {
@Schema(description = "生产计划ID")
private String productionPlanId;
@Schema(description = "生产计划名称")
private String productionPlanName;
@JsonFormat(pattern = "yyyy-MM-dd")
@Schema(description = "种植开始日期")
private LocalDate productionStartDate;
@JsonFormat(pattern = "yyyy-MM-dd")
@Schema(description = "种植结束日期")
private LocalDate productionEndDate;
@Schema(description = "基地中心点坐标")
private String centrePoint;
}

View File

@@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
/**
* @description: 种植计划 请求实体
* @author: binda
* @date: 2025/9/4 09:35
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmProductionPlanReqVO extends PageParam {
@Schema(description = "租户ID")
@NotNull(message = "租户ID不能为空")
private String tenantId;
@Schema(description = "种植开始日期")
private LocalDate productionStartDate;
@Schema(description = "种植结束日期")
private LocalDate productionEndDate;
// 初始化方法,可以在构造函数或 @PostConstruct 中调用
@PostConstruct
public void init() {
if (this.productionStartDate == null) {
this.productionStartDate = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
}
if (this.productionEndDate == null) {
this.productionEndDate = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
}
}
}

View File

@@ -0,0 +1,23 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 种植计划 响应实体
* @author: binda
* @date: 2025/9/4 09:34
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmProductionPlanRespVO {
@Schema(description = "生产计划ID")
private String productionPlanId;
@Schema(description = "生产计划名称")
private String productionPlanName;
}

View File

@@ -0,0 +1,24 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-统计图-种植计划完成情况 请求实体
* @author: binda
* @date: 2025/9/4 20:41
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PlantingPlanCompletionReqVO {
@Schema(description = "基地D")
@NotNull(message = "基地D: 不能为空")
private String baseId;
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-统计图-种植计划完成情况 响应实体
* @author: binda
* @date: 2025/9/4 20:41
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PlantingPlanCompletionRespVO {
@Schema(description = "未开始数量")
private Double notStartedRatio;
@Schema(description = "进行中数量")
private Double inProgressRatio;
@Schema(description = "已完成数量")
private Double completedRatio;
@Schema(description = "逾期数量")
private Double overdueRatio;
}

View File

@@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 数字驾驶舱-统计图-对比产量 请求实体
* @author: binda
* @date: 2025/9/4 19:41
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class YieldComparisonChartReqVO {
@Schema(description = "基地D")
@NotNull(message = "基地D: 不能为空")
private String baseId;
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.farm.controller.admin.api.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
/**
* @description: 数字驾驶舱-统计图-对比产量 响应实体
* @author: binda
* @date: 2025/9/4 19:40
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class YieldComparisonChartRespVO {
@Schema(description = "日期")
private Long date;
@Schema(description = "预计产量")
private Integer predictedYields;
@Schema(description = "实际产量")
private Integer practicalYields;
}

View File

@@ -23,7 +23,7 @@ public class BaseInfoPageReqVO extends PageParam {
@Schema(description = "面积") @Schema(description = "面积")
private BigDecimal area; private BigDecimal area;
@Schema(description = "json字符串保存") @Schema(description = "基地坐标")
private String point; private String point;
@Schema(description = "创建时间") @Schema(description = "创建时间")

View File

@@ -30,8 +30,8 @@ public class BaseInfoRespVO {
@ExcelProperty("面积") @ExcelProperty("面积")
private BigDecimal area; private BigDecimal area;
@Schema(description = "json字符串保存") @Schema(description = "基地坐标")
@ExcelProperty("json字符串保存") @ExcelProperty("基地坐标")
private String point; private String point;
@Schema(description = "创建时间") @Schema(description = "创建时间")

View File

@@ -21,7 +21,7 @@ public class BaseInfoSaveReqVO {
@Schema(description = "面积") @Schema(description = "面积")
private BigDecimal area; private BigDecimal area;
@Schema(description = "json字符串保存") @Schema(description = "基地坐标")
private String point; private String point;
@Schema(description = "租户编号", example = "27629") @Schema(description = "租户编号", example = "27629")

View File

@@ -41,9 +41,13 @@ public class BaseInfoDO extends BaseDO {
*/ */
private BigDecimal area; private BigDecimal area;
/** /**
* json字符串保存 * 基地坐标
*/ */
private String point; private String point;
/**
* 基地中心坐标
*/
private String centrePoint;
private String tenantId; private String tenantId;
} }

View File

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseInfoPageReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.math.BigDecimal; import java.math.BigDecimal;
@@ -30,5 +31,6 @@ public interface BaseInfoMapper extends BaseMapperX<BaseInfoDO> {
int getBaseCount(Long tenantId); int getBaseCount(Long tenantId);
BigDecimal getTotalBaseArea(String id, Long tenantId); BigDecimal getTotalBaseArea(@Param("id") String id, @Param("tenantId") Long tenantId);
} }

View File

@@ -3,13 +3,17 @@ package cn.iocoder.yudao.module.farm.dal.mysql.productionplan;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanPage2ReqVO; import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanPage2ReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanRespVO; import cn.iocoder.yudao.module.farm.controller.admin.cropFarmingCenter.vo.ProductionPlanRespVO;
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.dal.dataobject.productionplan.ProductionPlanDO; import cn.iocoder.yudao.module.farm.dal.dataobject.productionplan.ProductionPlanDO;
import cn.iocoder.yudao.module.farm.enums.CommonConstants;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List;
/** /**
* 种植中心-生产计划-生产计划 Mapper * 种植中心-生产计划-生产计划 Mapper
* *
@@ -48,5 +52,19 @@ public interface ProductionPlanMapper extends BaseMapperX<ProductionPlanDO> {
); );
} }
default PageResult<ProductionPlanDO> selectPage3(FarmProductionPlanReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ProductionPlanDO>()
.ge(ProductionPlanDO::getProductionStartDate, reqVO.getProductionStartDate())
.le(ProductionPlanDO::getProductionEndDate, reqVO.getProductionEndDate())
.eq(ProductionPlanDO::getTenantId, reqVO.getTenantId())
.eq(ProductionPlanDO::getPlanStatus, CommonConstants.PLAN_STATUS_3)
.orderByDesc(ProductionPlanDO::getCreateTime)
);
}
ProductionPlanRespVO.PlanOverview getPlanOverview(@Param("baseId") String baseId); ProductionPlanRespVO.PlanOverview getPlanOverview(@Param("baseId") String baseId);
List<YieldComparisonChartRespVO> getYieldComparisonChart(YieldComparisonChartReqVO req);
List<PlantingPlanCompletionRespVO> getPlantingPlanCompletionChart(PlantingPlanCompletionReqVO req);
} }

View File

@@ -1,6 +1,11 @@
package cn.iocoder.yudao.module.farm.service.baseinfo; package cn.iocoder.yudao.module.farm.service.baseinfo;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseInfoReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseInfoRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseOverviewReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseOverviewRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.*; import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.*;
import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
import jakarta.validation.Valid; import jakarta.validation.Valid;
@@ -75,4 +80,23 @@ public interface BaseInfoService {
* @return * @return
*/ */
TenantInfoRespVO getBaseOverviewInfo(); TenantInfoRespVO getBaseOverviewInfo();
/**
* 数字驾驶舱-获取基地概要信息
*
* @param req
* @return
*/
CommonResult<FarmBaseOverviewRespVO> getBaseOverview(FarmBaseOverviewReqVO req);
/**
* 获取基地总面积
* @param tenantId
* @return
*/
Double getBaseTotalArea(String tenantId);
Integer getBaseTotalCount(String tenantId);
CommonResult<List<FarmBaseInfoRespVO>> getBaseInfoList(FarmBaseInfoReqVO req);
} }

View File

@@ -1,9 +1,15 @@
package cn.iocoder.yudao.module.farm.service.baseinfo; package cn.iocoder.yudao.module.farm.service.baseinfo;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseInfoReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseInfoRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseOverviewReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmBaseOverviewRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.*; import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.*;
import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.gridinfo.GridInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.gridinfo.GridInfoDO;
@@ -14,11 +20,16 @@ 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.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.personnelmanagement.PersonnelManagementService;
import cn.iocoder.yudao.module.farm.service.plotinfo.PlotInfoService; import cn.iocoder.yudao.module.farm.service.plotinfo.PlotInfoService;
import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService; import cn.iocoder.yudao.module.farm.service.productionplan.ProductionPlanService;
import cn.iocoder.yudao.module.farm.service.specieslibrary.SpeciesLibraryService;
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 com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@@ -48,14 +59,19 @@ public class BaseInfoServiceImpl implements BaseInfoService {
@Resource @Resource
private SpeciesLibraryMapper speciesLibraryMapper; private SpeciesLibraryMapper speciesLibraryMapper;
@Resource @Resource
private SpeciesLibraryService speciesLibraryService;
@Resource
private PersonnelManagementMapper personnelManagementMapper; private PersonnelManagementMapper personnelManagementMapper;
@Resource @Resource
private PersonnelManagementService personnelManagementService;
@Resource
private GridInfoMapper gridInfoMapper; private GridInfoMapper gridInfoMapper;
@Resource @Resource
private ProductionPlanService productionPlanService; private ProductionPlanService productionPlanService;
@Resource @Resource
private PlotInfoService plotInfoService; private PlotInfoService plotInfoService;
@SneakyThrows
@Override @Override
public String createBaseInfo(BaseInfoSaveReqVO createReqVO) { public String createBaseInfo(BaseInfoSaveReqVO createReqVO) {
LoginUser user = getLoginUser(); LoginUser user = getLoginUser();
@@ -63,8 +79,12 @@ public class BaseInfoServiceImpl implements BaseInfoService {
BaseInfoDO baseInfo = BeanUtils.toBean(createReqVO, BaseInfoDO.class); BaseInfoDO baseInfo = BeanUtils.toBean(createReqVO, BaseInfoDO.class);
baseInfo.setId(IdUtil.fastUUID()); baseInfo.setId(IdUtil.fastUUID());
baseInfo.setTenantId(String.valueOf(user.getTenantId())); baseInfo.setTenantId(String.valueOf(user.getTenantId()));
baseInfoMapper.insert(baseInfo); // 解析坐标中心坐标
ObjectMapper objectMapper = new ObjectMapper();
JsonNode marker = objectMapper.readTree(baseInfo.getPoint()).get("marker");
baseInfo.setCentrePoint(marker.toString());
baseInfoMapper.insert(baseInfo);
// 返回 // 返回
return baseInfo.getId(); return baseInfo.getId();
} }
@@ -250,4 +270,67 @@ public class BaseInfoServiceImpl implements BaseInfoService {
} }
return gridInfos; return gridInfos;
} }
@Override
public CommonResult<FarmBaseOverviewRespVO> getBaseOverview(FarmBaseOverviewReqVO req) {
String tenantId = req.getTenantId();
String baseId = req.getBaseId();
BaseInfoDO bDO = baseInfoMapper.selectOne("id", baseId, "tenant_id", tenantId);
FarmBaseOverviewRespVO.TenantInfo tenantInfo = new FarmBaseOverviewRespVO.TenantInfo();
tenantInfo.setTenantId(bDO.getTenantId());
tenantInfo.setBaseTotalArea(this.getBaseTotalArea(tenantId));
tenantInfo.setBaseTotalCount(this.getBaseTotalCount(tenantId));
tenantInfo.setCropTotalCount(speciesLibraryService.getCropTotalCount(tenantId));
tenantInfo.setIotDeviceTotalCount(0); // TODO: 2025/9/4
FarmBaseOverviewRespVO.BaseInfo baseInfo = new FarmBaseOverviewRespVO.BaseInfo();
baseInfo.setBaseId(bDO.getId());
baseInfo.setBaseName(bDO.getName());
baseInfo.setBaseArea(bDO.getArea().doubleValue());
baseInfo.setBasePoint(bDO.getPoint());
baseInfo.setBaseCentrePoint(bDO.getCentrePoint());
baseInfo.setPlantingCropCount(productionPlanService.getGrowingCropCount(baseId));
baseInfo.setPlantingPlotCount(productionPlanService.getGrowingPlotCount(baseId));
baseInfo.setIotDeviceCount(0); // TODO: 2025/9/4
baseInfo.setPlantingTaskCount(productionPlanService.getGrowingPlanCount(baseId));
baseInfo.setAdministratorName(getAdministratorName(tenantId, bDO.getManager()));
return CommonResult.success(new FarmBaseOverviewRespVO(tenantInfo, baseInfo));
}
private String getAdministratorName(String tenantId, String manager) {
List<PersonnelManagementDO> personnelList = personnelManagementMapper.selectList("tenant_id", tenantId);
Map<String, String> employeeMap = personnelList.stream().collect(Collectors.toMap(PersonnelManagementDO::getId, PersonnelManagementDO::getName, (v1, v2) -> v1));
return personnelManagementService.getEmployeeNameMap(employeeMap, manager);
}
@Override
public Double getBaseTotalArea(String tenantId) {
BigDecimal d = baseInfoMapper.getTotalBaseArea(null, Long.valueOf(tenantId));
return d.doubleValue();
}
@Override
public Integer getBaseTotalCount(String tenantId) {
return baseInfoMapper.getBaseCount(Long.valueOf(tenantId));
}
@Override
public CommonResult<List<FarmBaseInfoRespVO>> getBaseInfoList(FarmBaseInfoReqVO req) {
LambdaQueryWrapperX<BaseInfoDO> wrapperX = new LambdaQueryWrapperX<>();
wrapperX.eq(BaseInfoDO::getTenantId, req.getTenantId());
wrapperX.eq(BaseInfoDO::getDeleted, CommonConstants.NO_CODE);
List<BaseInfoDO> list = baseInfoMapper.selectList(wrapperX);
List<FarmBaseInfoRespVO> vos = list.stream().map(e -> {
FarmBaseInfoRespVO vo = new FarmBaseInfoRespVO();
vo.setBaseId(e.getId());
vo.setBaseName(e.getName());
vo.setBasePoint(e.getPoint());
vo.setBaseCentrePoint(e.getCentrePoint());
return vo;
}).collect(Collectors.toList());
return CommonResult.success(vos);
}
} }

View File

@@ -158,6 +158,7 @@ public class HomeServiceImpl implements HomeService {
PlotOrCropInfo t = new PlotOrCropInfo(); PlotOrCropInfo t = new PlotOrCropInfo();
t.setLabel(label); t.setLabel(label);
t.setBaseId(e.getBaseId()); t.setBaseId(e.getBaseId());
t.setBaseName(e.getBaseName());
t.setPlotId(e.getPlotId()); t.setPlotId(e.getPlotId());
t.setPlotName(e.getPlotName()); t.setPlotName(e.getPlotName());
t.setGrowFlag(growFlag); t.setGrowFlag(growFlag);

View File

@@ -1,5 +1,7 @@
package cn.iocoder.yudao.module.farm.service.productionplan; package cn.iocoder.yudao.module.farm.service.productionplan;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseNamePlanRespVO; import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseNamePlanRespVO;
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;
@@ -123,6 +125,8 @@ public interface ProductionPlanService {
int getGrowingCropCount(String baseId); int getGrowingCropCount(String baseId);
int getGrowingCropCount(String baseId,String plotId); int getGrowingCropCount(String baseId,String plotId);
int getGrowingPlanCount(String baseId);
/** /**
* 计算在种地块面积 * 计算在种地块面积
* @param baseId * @param baseId
@@ -149,4 +153,39 @@ public interface ProductionPlanService {
Integer getTodayTaskCount(String baseId); Integer getTodayTaskCount(String baseId);
/**
* api 接口
* 生产计划-分页查询
*
* @param req
* @return
*/
CommonResult<PageResult<FarmProductionPlanRespVO>> getPageForFarmProductionPlan(FarmProductionPlanReqVO req);
/**
* api 接口
* 生产计划-详情查询
*
* @param req
* @return
*/
CommonResult<FarmProductionPlanDetailRespVO> getDetailForFarmProductionPlan(FarmProductionPlanDetailReqVO req);
/**
* api 接口
* 生产数据-产量对比
*
* @param req
* @return
*/
CommonResult<List<YieldComparisonChartRespVO>> getYieldComparisonChart(YieldComparisonChartReqVO req);
/**
* api 接口
* 生产数据-种植计划完成情况
*
* @param req
* @return
*/
CommonResult<List<PlantingPlanCompletionRespVO>> getPlantingPlanCompletionChart(PlantingPlanCompletionReqVO req);
} }

View File

@@ -2,11 +2,15 @@ package cn.iocoder.yudao.module.farm.service.productionplan;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseNamePlanRespVO; import cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo.BaseNamePlanRespVO;
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 cn.iocoder.yudao.module.farm.dal.dataobject.baseinfo.BaseInfoDO;
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.baseinfo.BaseInfoMapper;
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.utils.DateUtils; import cn.iocoder.yudao.module.farm.utils.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@@ -25,6 +29,8 @@ 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.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -46,6 +52,8 @@ public class ProductionPlanServiceImpl implements ProductionPlanService {
private ProductionPlanMapper productionPlanMapper; private ProductionPlanMapper productionPlanMapper;
@Resource @Resource
private SpeciesLibraryMapper speciesLibraryMapper; private SpeciesLibraryMapper speciesLibraryMapper;
@Resource
private BaseInfoMapper baseInfoMapper;
@Override @Override
public String createProductionPlan(ProductionPlanSaveReqVO createReqVO) { public String createProductionPlan(ProductionPlanSaveReqVO createReqVO) {
@@ -121,8 +129,7 @@ public class ProductionPlanServiceImpl implements ProductionPlanService {
@Override @Override
public PageResult<ProductionPlanDO> getProductionPlanPage(ProductionPlanPageReqVO pageReqVO) { public PageResult<ProductionPlanDO> getProductionPlanPage(ProductionPlanPageReqVO pageReqVO) {
productionPlanMapper.selectPage(pageReqVO); return productionPlanMapper.selectPage(pageReqVO);
return null;
} }
@Override @Override
@@ -252,6 +259,15 @@ public class ProductionPlanServiceImpl implements ProductionPlanService {
.count(); .count();
} }
@Override
public int getGrowingPlanCount(String baseId) {
List<ProductionPlanDO> planList = productionPlanMapper.selectList("base_id", baseId);
return (int) planList.stream()
.filter(Objects::nonNull)
.filter(plan -> Objects.equals(plan.getPlanStatus(), PLAN_STATUS_2))
.count();
}
@Override @Override
public double getPredictedArea(String plotId,BigDecimal plotArea) { public double getPredictedArea(String plotId,BigDecimal plotArea) {
@@ -327,4 +343,47 @@ public class ProductionPlanServiceImpl implements ProductionPlanService {
} }
return count; return count;
} }
@Override
public CommonResult<PageResult<FarmProductionPlanRespVO>> getPageForFarmProductionPlan(FarmProductionPlanReqVO req) {
if (req.getProductionStartDate() == null || req.getProductionEndDate() == null) {
req.setProductionStartDate(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()));
req.setProductionEndDate( LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()));
}
PageResult<ProductionPlanDO> page = productionPlanMapper.selectPage3(req);
Long total = page.getTotal();
List<FarmProductionPlanRespVO> respList = page.getList().stream().map(e -> new FarmProductionPlanRespVO(e.getId(), e.getPlanNumber())).toList();
return CommonResult.success(new PageResult<>(respList, total));
}
@Override
public CommonResult<FarmProductionPlanDetailRespVO> getDetailForFarmProductionPlan(FarmProductionPlanDetailReqVO req) {
ProductionPlanDO planDO = productionPlanMapper.selectOne("id", req.getProductionPlanId(), "tenant_id", req.getTenantId());
BaseInfoDO baseDO = baseInfoMapper.selectOne("id", planDO.getBaseId());
FarmProductionPlanDetailRespVO res = new FarmProductionPlanDetailRespVO();
res.setProductionPlanId(planDO.getId());
res.setProductionPlanName(planDO.getPlanNumber());
res.setProductionStartDate(planDO.getProductionStartDate());
res.setProductionEndDate(planDO.getProductionEndDate());
res.setCentrePoint(baseDO.getCentrePoint());
return CommonResult.success(res);
}
@Override
public CommonResult<List<YieldComparisonChartRespVO>> getYieldComparisonChart(YieldComparisonChartReqVO req) {
List<YieldComparisonChartRespVO> res = productionPlanMapper.getYieldComparisonChart(req);
return CommonResult.success(res);
}
@Override
public CommonResult<List<PlantingPlanCompletionRespVO>> getPlantingPlanCompletionChart(PlantingPlanCompletionReqVO req) {
List<PlantingPlanCompletionRespVO> res = productionPlanMapper.getPlantingPlanCompletionChart(req);
return CommonResult.success(res);
}
} }

View File

@@ -79,4 +79,11 @@ public interface SpeciesLibraryService {
* @return * @return
*/ */
List<SpeciesAndModelTreeRespVO> getSpeciesAndModelTree(); List<SpeciesAndModelTreeRespVO> getSpeciesAndModelTree();
/**
* 获取品种总数
* @param tenantId
* @return
*/
Integer getCropTotalCount(String tenantId);
} }

View File

@@ -20,6 +20,7 @@ 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 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 com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -37,6 +38,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
import static cn.iocoder.yudao.module.farm.enums.CommonConstants.DICT_TYPE_CODE_3; import static cn.iocoder.yudao.module.farm.enums.CommonConstants.DICT_TYPE_CODE_3;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.SPECIES_LIBRARY_NOT_EXISTS; import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.SPECIES_LIBRARY_NOT_EXISTS;
import static cn.iocoder.yudao.module.farm.utils.StrHelperUtil.generate; import static cn.iocoder.yudao.module.farm.utils.StrHelperUtil.generate;
import static com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery;
/** /**
* 物种库维护 Service 实现类 * 物种库维护 Service 实现类
@@ -395,4 +397,20 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public Integer getCropTotalCount(String tenantId) {
QueryWrapper<SpeciesLibraryDO> wrapper = new QueryWrapper<>();
wrapper.select("COUNT(DISTINCT cultivar_name) as count")
.eq("tenant_id", tenantId)
.eq("deleted", CommonConstants.NO_CODE)
.isNotNull("cultivar_name")
.ne("cultivar_name", "");
List<Map<String, Object>> result = speciesLibraryMapper.selectMaps(wrapper);
if (!result.isEmpty()) {
return ((Long) result.get(0).get("count")).intValue();
}
return 0;
}
} }

View File

@@ -26,6 +26,9 @@
<if test="id != null and id != ''"> <if test="id != null and id != ''">
AND id = #{id} AND id = #{id}
</if> </if>
<if test="tenantId != null and tenantId != ''">
AND tenant_id = #{tenantId}
</if>
</where> </where>
</select> </select>
</mapper> </mapper>

View File

@@ -41,4 +41,45 @@
</where> </where>
GROUP BY base_id GROUP BY base_id
</select> </select>
<select id="getYieldComparisonChart"
parameterType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.YieldComparisonChartReqVO"
resultType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.YieldComparisonChartRespVO">
SELECT
YEAR(production_end_date) AS date,
SUM(predicted_yields) AS predictedYields,
SUM(practical_yields) AS practicalYields
FROM farm_production_plan
<where>
plan_status = 3
AND deleted = 0
AND production_end_date IS NOT NULL
<if test="tenantId != null and tenantId != ''">AND tenant_id = #{tenantId}</if>
<if test="baseId != null and baseId != ''">AND base_id = #{baseId}</if>
</where>
GROUP BY YEAR(production_end_date)
ORDER BY date
</select>
<select id="getPlantingPlanCompletionChart"
parameterType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.PlantingPlanCompletionReqVO"
resultType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.PlantingPlanCompletionRespVO">
SELECT
ROUND(SUM(CASE WHEN plan_status = 1 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS notStartedRatio,
ROUND(SUM(CASE WHEN plan_status = 2 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS inProgressRatio,
ROUND(SUM(CASE WHEN plan_status = 3 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS completedRatio,
ROUND(SUM(CASE WHEN plan_status = 4 THEN 1 ELSE 0 END) * 100.0 / COUNT(*), 2) AS overdueRatio
FROM farm_production_plan
<where>
deleted = 0
AND plan_status IN (1, 2, 3, 4)
<if test="tenantId != null and tenantId != ''">AND tenant_id = #{tenantId}</if>
<if test="baseId != null and baseId != ''">AND base_id = #{baseId}</if>
</where>
</select>
</mapper> </mapper>