feat (farm): 远程接口API

- 数字驾驶舱-基地与设备信息列表
- 数字驾驶舱-灾害统计-农事分布
- 数字驾驶舱-设备总览
This commit is contained in:
达富斌
2025-09-25 16:47:58 +08:00
parent 33eb3f5b6c
commit 2b85f82495
21 changed files with 418 additions and 36 deletions

View File

@@ -2,17 +2,17 @@ package cn.iocoder.yudao.module.farm.controller.admin.api;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; 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.module.farm.controller.admin.api.vo.*; import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
import cn.iocoder.yudao.module.farm.service.baseinfo.BaseInfoService; import cn.iocoder.yudao.module.farm.service.baseinfo.BaseInfoService;
import cn.iocoder.yudao.module.farm.service.deviceinfo.DeviceInfoService; import cn.iocoder.yudao.module.farm.service.deviceinfo.DeviceInfoService;
import cn.iocoder.yudao.module.farm.service.farmingrecord.FarmingRecordService; import cn.iocoder.yudao.module.farm.service.farmingrecord.FarmingRecordService;
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.screendisasterdata.ScreenDisasterDataService; import cn.iocoder.yudao.module.farm.service.screendisasterdata.ScreenDisasterDataService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestBody;
@@ -20,6 +20,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
import java.util.Map;
import static cn.iocoder.yudao.module.farm.enums.CommonConstants.DEVICE_STATE_MAP;
/** /**
* @description: api 接口 * @description: api 接口
@@ -86,6 +89,28 @@ public class ApiController {
return baseInfoService.getBaseInfoList(req); return baseInfoService.getBaseInfoList(req);
} }
@PostMapping("/digital-cockpit/baseAndDevice/list")
@Operation(summary = "数字驾驶舱-基地与设备信息列表")
public CommonResult<List<FarmBaseAndDeviceInfoRespVO>> getBaseAndDeviceInfoList(@Valid @RequestBody FarmBaseAndDeviceInfoReqVO req) {
CommonResult<List<FarmBaseInfoRespVO>> bResult = baseInfoService.getBaseInfoList(new FarmBaseInfoReqVO(req.getTenantId()));
List<FarmBaseAndDeviceInfoRespVO> dList = BeanUtils.toBean(bResult.getData(), FarmBaseAndDeviceInfoRespVO.class);
Map<String, String> dtNameMap = deviceInfoService.getDeviceTypeNameMap(req.getTenantId());
dList.forEach(e -> {
List<DeviceInfoDO> sourceList = deviceInfoService.getBaseAndDeviceInfoList(e.getBaseId());
List<FarmBaseAndDeviceInfoRespVO.DeviceInfo> targetList = sourceList.stream().map(d ->{
FarmBaseAndDeviceInfoRespVO.DeviceInfo target = BeanUtils.toBean(d, FarmBaseAndDeviceInfoRespVO.DeviceInfo.class);
// code -> name
target.setDeviceTypeName(dtNameMap.getOrDefault(d.getDeviceType(), ""));
target.setDeviceStateName(DEVICE_STATE_MAP.getOrDefault(d.getDeviceState(),""));
return target;
}).toList();
e.setDeviceInfoList(targetList);
});
return CommonResult.success(dList);
}
@PostMapping("/digital-cockpit/chart/yield-comparison") @PostMapping("/digital-cockpit/chart/yield-comparison")
@Operation(summary = "数字驾驶舱-生产数据-产量对比") @Operation(summary = "数字驾驶舱-生产数据-产量对比")
public CommonResult<List<YieldComparisonChartRespVO>> getYieldComparisonChart(@Valid @RequestBody YieldComparisonChartReqVO req) { public CommonResult<List<YieldComparisonChartRespVO>> getYieldComparisonChart(@Valid @RequestBody YieldComparisonChartReqVO req) {
@@ -106,14 +131,23 @@ public class ApiController {
@PostMapping("/digital-cockpit/chart/farming-distribution") @PostMapping("/digital-cockpit/chart/farming-distribution")
@Operation(summary = "数字驾驶舱-灾害统计-农事分布") @Operation(summary = "数字驾驶舱-灾害统计-农事分布")
public CommonResult<List<FarmingDistributionRespVO>> getFarmingDistributionChart(@Valid @RequestBody FarmingDistributionReqVO req) { public CommonResult<FarmingDistributionRespVO> getFarmingDistributionChart(@Valid @RequestBody FarmingDistributionReqVO req) {
return farmingRecordService.getFarmingDistributionChart(req); // TODO: 2025/9/4 未实现 return farmingRecordService.getFarmingDistributionChart(req);
} }
@PostMapping("/digital-cockpit/chart/device-state") @PostMapping("/digital-cockpit/chart/device-state")
@Operation(summary = "数字驾驶舱-设备总览") @Operation(summary = "数字驾驶舱-设备总览")
public CommonResult<DeviceStateRespVO> getDeviceStateStatistics(@Valid @RequestBody DeviceStateReqVO req) { public CommonResult<DeviceStateRespVO> getDeviceStateStatistics(@Valid @RequestBody DeviceStateReqVO req) {
return deviceInfoService.getDeviceStateStatistics(req); // TODO: 2025/9/24 return deviceInfoService.getDeviceStateStatistics(req);
} }
@PostMapping("/digital-cockpit/chart/device-monitoring")
@Operation(summary = "数字驾驶舱-设备监测")
public CommonResult<DeviceMonitoringRespVO> getDeviceMonitoring(@Valid @RequestBody DeviceMonitoringReqVO req) {
return deviceInfoService.getDeviceMonitoring(req);// TODO: 2025/9/25
}
} }

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/25 10:58
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeviceMonitoringReqVO {
@Schema(description = "基地D")
@NotNull(message = "基地D: 不能为空")
private String baseId;
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,55 @@
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/25 10:55
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DeviceMonitoringRespVO {
private String baseName;
private DeviceMonitoringInfo deviceMonitoringInfo ;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class DeviceMonitoringInfo{
@Schema(description = "节点编号")
private Integer nodeId;
@Schema(description = "节点名称")
private String nodeName;
@Schema(description = "节点类型")
private Integer nodeType;
// 模拟量1 名称,单位,原值,显示值,报警等级
@Schema(description = "temName" , example = "温度")
private String temName;
@Schema(description = "temUnit" , example = "`C")
private String temUnit;
@Schema(description = "temValue" , example = "28.100000381469727")
private Double temValue;
@Schema(description = "temValueStr" , example = "30.2")
private String temValueStr;
@Schema(description = "temAlarmStatus" , example = "0")
private Integer temAlarmStatus;
// 模拟量2 名称,单位,原值,显示值,报警等级
@Schema(description = "humName" , example = "湿度")
private String humName;
@Schema(description = "humUnit" , example = "%RH")
private String humUnit;
@Schema(description = "humValue" , example = "13.699999809265137")
private String humValue;
@Schema(description = "humValueStr" , example = "13.7")
private String humValueStr;
@Schema(description = "humAlarmStatus" , example = "0")
private String humAlarmStatus;
}
}

View File

@@ -5,6 +5,8 @@ import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.util.List;
/** /**
* @description: 设备状态 * @description: 设备状态
* @author: binda * @author: binda
@@ -20,6 +22,8 @@ public class DeviceStateRespVO {
private Integer totalOnlineDevices; private Integer totalOnlineDevices;
@Schema(description = "离线设备总数") @Schema(description = "离线设备总数")
private Integer totalOfflineDevices; private Integer totalOfflineDevices;
@Schema(description = "设备类型")
private List<DeviceType> deviceTypeList;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@@ -28,6 +32,6 @@ public class DeviceStateRespVO {
@Schema(description = "设备类型名称") @Schema(description = "设备类型名称")
private String deviceTypeName; private String deviceTypeName;
@Schema(description = "设备数量") @Schema(description = "设备数量")
private Integer deviceCount; private Long deviceCount;
} }
} }

View File

@@ -0,0 +1,21 @@
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/25 14:09
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmBaseAndDeviceInfoReqVO {
@Schema(description = "租户ID")
@NotNull(message = "租户ID: 不能为空")
private String tenantId;
}

View File

@@ -0,0 +1,45 @@
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.util.List;
/**
* @description:
* @author: binda
* @date: 2025/9/25 14:09
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FarmBaseAndDeviceInfoRespVO {
@Schema(description = "基地ID")
private String baseId;
@Schema(description = "基地名称")
private String baseName;
@Schema(description = "基地范围坐标")
private String basePoint;
@Schema(description = "基地中心坐标")
private String baseCentrePoint;
@Schema(description = "设备坐标")
private List<DeviceInfo> deviceInfoList;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class DeviceInfo{
@Schema(description = "设备类型名称")
private String deviceTypeName;
@Schema(description = "设备编号")
private String deviceUniqueId;
@Schema(description = "关联地块")
private String plotName;
@Schema(description = "设备坐标")
private String point;
@Schema(description = "设备状态 (0:未激活,1:在线,2:离线,3:维护中,4:故障)")
private String deviceStateName;
}
}

View File

@@ -16,12 +16,10 @@ import lombok.NoArgsConstructor;
public class FarmingDistributionRespVO { public class FarmingDistributionRespVO {
@Schema(description = "总数") @Schema(description = "总数")
private Integer totalCount; private Integer totalCount;
@Schema(description = "已逾期") @Schema(description = "未开始")
private Integer overdueStatusCount; private Integer notStart;
@Schema(description = "已完成")
private Integer completedStatusCount;
@Schema(description = "未完成")
private Integer pendingStatusCount;
@Schema(description = "执行中") @Schema(description = "执行中")
private Integer executingStatusCount; private Integer executingStatusCount;
@Schema(description = "已完成")
private Integer completedStatusCount;
} }

View File

@@ -1,10 +1,12 @@
package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2; package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/** /**
@@ -39,8 +41,11 @@ public class DeviceInfoDetailV2RespVO {
private Integer isIotCardExisted; private Integer isIotCardExisted;
@Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障")
private Integer deviceState; private Integer deviceState;
@Schema(description = "设备状态名称")
private String deviceStateName;
@Schema(description = "绑定状态:1: 绑定; 0: 未绑定") @Schema(description = "绑定状态:1: 绑定; 0: 未绑定")
private Integer bindingState; private Integer bindingState;
private String bindingStateName;
@Schema(description = "设备坐标") @Schema(description = "设备坐标")
private String point; private String point;
@@ -69,21 +74,84 @@ public class DeviceInfoDetailV2RespVO {
public static class SoilInfo{ public static class SoilInfo{
private String deviceUniqueId; private String deviceUniqueId;
private RealTimeData realTimeData; private RealTimeData realTimeData;
private List<HistoryDataListPage> historyDataListPages; private List<HistoryDataList> historyDataLis;
} }
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public static class RealTimeData{ public static class RealTimeData{
private String code; @Schema(description = "设备地址")
private String deviceAddr;
@Schema(description = "设备名称")
private String deviceName;
@Schema(description = "设备状态", example = "online")
private String status;
@Schema(description = "设备类型", example = "soil(土壤墒情)")
private String deviceType;
@Schema(description = "数据集合")
private List<RealData> realDataList;
} }
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
public static class HistoryDataListPage{ public static class RealData{
private String code; @Schema(description = "节点编号")
private Integer nodeId;
@Schema(description = "节点名称")
private String nodeName;
@Schema(description = "节点类型")
private Integer nodeType;
// 模拟量1 名称,单位,原值,显示值,报警等级
@Schema(description = "temName" , example = "温度")
private String temName;
@Schema(description = "temUnit" , example = "`C")
private String temUnit;
@Schema(description = "temValue" , example = "28.100000381469727")
private Double temValue;
@Schema(description = "temValueStr" , example = "30.2")
private String temValueStr;
@Schema(description = "temAlarmStatus" , example = "0")
private Integer temAlarmStatus;
// 模拟量2 名称,单位,原值,显示值,报警等级
@Schema(description = "humName" , example = "湿度")
private String humName;
@Schema(description = "humUnit" , example = "%RH")
private String humUnit;
@Schema(description = "humValue" , example = "13.699999809265137")
private String humValue;
@Schema(description = "humValueStr" , example = "13.7")
private String humValueStr;
@Schema(description = "humAlarmStatus" , example = "0")
private String humAlarmStatus;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class HistoryDataList {
@Schema(description = "历史记录ID")
private Integer historyId;
@Schema(description = "历史记录时间")
@JsonFormat(pattern = "yyyy-MM-dd hh:MM:ss")
private LocalDateTime recordTime;
@Schema(description = "设备地址")
private String deviceAddress;
@Schema(description = "警告状态")
private Integer alarmStatus;
@Schema(description = "警告状态 (0:正常 1:报警)")
private String alarmStatusName;
@Schema(description = "模拟量1 (字符)")
private String temStr;
@Schema(description = "模拟量1 (值)")
private Double temValue;
@Schema(description = "模拟量2 (字符)")
private String humStr;
@Schema(description = "模拟量2 (值)")
private Double humValue;
} }
@Data @Data

View File

@@ -105,11 +105,11 @@ public class DigitalCockpitController {
@Parameter(name = "baseId", description = "基地ID", required = true) @Parameter(name = "baseId", description = "基地ID", required = true)
public CommonResult<VariousIndexesRespVO> getVariousIndexes(@RequestParam("baseId") String baseId) { public CommonResult<VariousIndexesRespVO> getVariousIndexes(@RequestParam("baseId") String baseId) {
// TODO: 2025/9/24 待实现 // TODO: 2025/9/24 待实现
int weatherAlertCount = 0; int weatherAlertCount = 10;
int pestAlertCount = 0; int pestAlertCount = 11;
int environmentalAlertCount = 0; int environmentalAlertCount = 12;
int deviceAlertCount = 0; int deviceAlertCount = 13;
int farmingReminderCount = 0; int farmingReminderCount = 14;
return success(new VariousIndexesRespVO(weatherAlertCount, pestAlertCount, environmentalAlertCount, deviceAlertCount, farmingReminderCount)); return success(new VariousIndexesRespVO(weatherAlertCount, pestAlertCount, environmentalAlertCount, deviceAlertCount, farmingReminderCount));
} }

View File

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo;
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.DeviceStateRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceStatisticsRespVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceStatisticsRespVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
@@ -95,4 +96,11 @@ public interface DeviceInfoMapper extends BaseMapperX<DeviceInfoDO> {
*/ */
DeviceStatisticsRespVO getStatisticsInfo(@Param("baseId") String baseId, DeviceStatisticsRespVO getStatisticsInfo(@Param("baseId") String baseId,
@Param("tenantId") String tenantId); @Param("tenantId") String tenantId);
/**
* 设备在线状态统计
* @param tenantId
* @return
*/
DeviceStateRespVO countDeviceState(String tenantId);
} }

View File

@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.farm.dal.mysql.farmingrecord;
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.FarmingDistributionReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmingDistributionRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.farmingrecord.vo.FarmingRecordPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.farmingrecord.vo.FarmingRecordPageReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.farmingrecord.FarmingRecordDO; import cn.iocoder.yudao.module.farm.dal.dataobject.farmingrecord.FarmingRecordDO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@@ -37,4 +39,5 @@ public interface FarmingRecordMapper extends BaseMapperX<FarmingRecordDO> {
.orderByDesc(FarmingRecordDO::getTaskTime)); .orderByDesc(FarmingRecordDO::getTaskTime));
} }
FarmingDistributionRespVO getFarmingDistributionChart(FarmingDistributionReqVO req);
} }

View File

@@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.farm.manager.devices; package cn.iocoder.yudao.module.farm.manager.devices;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceInfoDetailV2RespVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceInfoDetailV2RespVO;
import cn.iocoder.yudao.module.farm.manager.devices.soil.SoilService; import cn.iocoder.yudao.module.farm.manager.devices.soil.SoilService;
import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.HistoryDataListPageReqVO; import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.HistoryDataListPageReqVO;
@@ -7,12 +8,14 @@ import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.HistoryDataListPage
import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.RealTimeDataReqVO; import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.RealTimeDataReqVO;
import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.RealTimeDataRespVO; import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.RealTimeDataRespVO;
import cn.iocoder.yudao.module.farm.manager.devices.wf.WaterFertilizerService; import cn.iocoder.yudao.module.farm.manager.devices.wf.WaterFertilizerService;
import cn.iocoder.yudao.module.farm.utils.DateUtils;
import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
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.manager.devices.commons.DeviceConst.ALARM_STATUS_NAME_MAP;
/** /**
* @description: 设备管理 * @description: 设备管理
@@ -58,19 +61,30 @@ public class DeviceManager {
if (ObjectUtils.isEmpty(realTimeData)) { if (ObjectUtils.isEmpty(realTimeData)) {
return null; return null;
} }
RealTimeDataRespVO sourceObj = realTimeData.get(0);
return BeanUtils.toBean(sourceObj, DeviceInfoDetailV2RespVO.RealTimeData.class);
return null;
} }
public List<DeviceInfoDetailV2RespVO.HistoryDataListPage> coverToSoil(HistoryDataListPageRespVO historyDataList ) { public List<DeviceInfoDetailV2RespVO.HistoryDataList> coverToSoil(HistoryDataListPageRespVO historyDataList ) {
if (ObjectUtils.isEmpty(historyDataList)) { if (ObjectUtils.isEmpty(historyDataList)) {
return null; return null;
} }
List<HistoryDataListPageRespVO.Row> source = historyDataList.getRows();
return source.stream().map(e -> {
DeviceInfoDetailV2RespVO.HistoryDataList target = new DeviceInfoDetailV2RespVO.HistoryDataList();
target.setHistoryId(e.getHistoryId());
target.setRecordTime(DateUtils.timestampToLocalDateTime(e.getRecordTime()));
target.setDeviceAddress(e.getDeviceAddress());
target.setAlarmStatus(e.getAlarmStatus());
target.setAlarmStatusName(ALARM_STATUS_NAME_MAP.getOrDefault(e.getAlarmStatus(),""));
target.setTemStr(e.getTemStr());
target.setTemValue(e.getTemValue());
target.setHumStr(e.getHumStr());
target.setHumValue(e.getHumValue());
return target;
}).toList();
return null;
} }

View File

@@ -1,5 +1,8 @@
package cn.iocoder.yudao.module.farm.manager.devices.commons; package cn.iocoder.yudao.module.farm.manager.devices.commons;
import java.util.HashMap;
import java.util.Map;
/** /**
* @description: 设备常量 * @description: 设备常量
* @author: binda * @author: binda
@@ -74,6 +77,19 @@ public class DeviceConst {
public final int NOTICE_TYPE_0 = 0; // 邮箱 public final int NOTICE_TYPE_0 = 0; // 邮箱
public final int NOTICE_TYPE_1 = 1; // 短信 public final int NOTICE_TYPE_1 = 1; // 短信
public final static int ALARM_STATUS_NAME_0 = 0; // 正常
public final static int ALARM_STATUS_NAME_1 = 1; // 报警
// TODO: 2025/9/17 UpdateNodeInfoReqVO // TODO: 2025/9/17 UpdateNodeInfoReqVO
public static Map<Integer, String> ALARM_STATUS_NAME_MAP = new HashMap<>();
static {
ALARM_STATUS_NAME_MAP.put(ALARM_STATUS_NAME_0, "正常");
ALARM_STATUS_NAME_MAP.put(ALARM_STATUS_NAME_1, "报警");
}
} }

View File

@@ -1,8 +1,7 @@
package cn.iocoder.yudao.module.farm.service.deviceinfo; package cn.iocoder.yudao.module.farm.service.deviceinfo;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.DeviceStateReqVO; import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.DeviceStateRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceInfoDetailV2RespVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceInfoDetailV2RespVO;
@@ -13,6 +12,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* 设备信息 Service 接口 * 设备信息 Service 接口
@@ -86,4 +86,23 @@ public interface DeviceInfoService {
* @return * @return
*/ */
CommonResult<DeviceStateRespVO> getDeviceStateStatistics(DeviceStateReqVO req); CommonResult<DeviceStateRespVO> getDeviceStateStatistics(DeviceStateReqVO req);
/**
* api接口
* 设备监控
* @param req
* @return
*/
CommonResult<DeviceMonitoringRespVO> getDeviceMonitoring(DeviceMonitoringReqVO req);
/**
* api接口
* 基地与设备坐标
*
* @param req
* @return
*/
List<DeviceInfoDO> getBaseAndDeviceInfoList(String baseId);
Map<String, String> getDeviceTypeNameMap(String tenantId);
} }

View File

@@ -3,8 +3,7 @@ package cn.iocoder.yudao.module.farm.service.deviceinfo;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
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.CommonResult;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.DeviceStateReqVO; import cn.iocoder.yudao.module.farm.controller.admin.api.vo.*;
import cn.iocoder.yudao.module.farm.controller.admin.api.vo.DeviceStateRespVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO;
import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceInfoDetailV2RespVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceInfoDetailV2RespVO;
@@ -29,11 +28,13 @@ import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo.DeviceInfoMapper; import cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo.DeviceInfoMapper;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; 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.common.pojo.CommonResult.success;
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.DEVICE_CLASS_TYPE_ERROR; import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.DEVICE_CLASS_TYPE_ERROR;
import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.DEVICE_INFO_NOT_EXISTS; import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.DEVICE_INFO_NOT_EXISTS;
@@ -169,7 +170,38 @@ public class DeviceInfoServiceImpl implements DeviceInfoService {
@Override @Override
public CommonResult<DeviceStateRespVO> getDeviceStateStatistics(DeviceStateReqVO req) { public CommonResult<DeviceStateRespVO> getDeviceStateStatistics(DeviceStateReqVO req) {
Map<String, String> dtNameMap = this.getDeviceTypeNameMap(req.getTenantId());
List<DeviceInfoDO> dList = deviceInfoMapper.selectList(DeviceInfoDO::getTenantId, req.getTenantId());
Map<String, Long> countByDeviceType = dList.stream().collect(Collectors.groupingBy(DeviceInfoDO::getDeviceType, Collectors.counting()));
List<DeviceStateRespVO.DeviceType> dtList = new ArrayList<>();
for (Map.Entry<String, Long> entry : countByDeviceType.entrySet()) {
String v1 = dtNameMap.get(entry.getKey());
Long v2 = entry.getValue();
dtList.add(new DeviceStateRespVO.DeviceType(v1, v2));
}
DeviceStateRespVO res = deviceInfoMapper.countDeviceState(req.getTenantId());
res.setDeviceTypeList(dtList);
return success(res);
}
@Override
public CommonResult<DeviceMonitoringRespVO> getDeviceMonitoring(DeviceMonitoringReqVO req) {
return null; return null;
} }
@Override
public List<DeviceInfoDO> getBaseAndDeviceInfoList(String baseId) {
return deviceInfoMapper.selectList(DeviceInfoDO::getBaseId,baseId);
}
@Override
public Map<String, String> getDeviceTypeNameMap(String tenantId) {
List<DeviceClassifyDO> deviceClassifyDOS = deviceClassifyMapper.selectList(DeviceClassifyDO::getTenantId, tenantId);
return deviceClassifyDOS.stream()
.filter(device -> device.getParentId() != null && device.getParentId() == 0)
.collect(Collectors.toMap(e -> e.getId().toString(), DeviceClassifyDO::getName));
}
} }

View File

@@ -92,6 +92,6 @@ public interface FarmingRecordService {
* @param req * @param req
* @return * @return
*/ */
CommonResult<List<FarmingDistributionRespVO>> getFarmingDistributionChart(FarmingDistributionReqVO req); CommonResult<FarmingDistributionRespVO> getFarmingDistributionChart(FarmingDistributionReqVO req);
} }

View File

@@ -268,7 +268,8 @@ public class FarmingRecordServiceImpl implements FarmingRecordService {
} }
@Override @Override
public CommonResult<List<FarmingDistributionRespVO>> getFarmingDistributionChart(FarmingDistributionReqVO req) { public CommonResult<FarmingDistributionRespVO> getFarmingDistributionChart(FarmingDistributionReqVO req) {
return null; FarmingDistributionRespVO res = farmingRecordMapper.getFarmingDistributionChart(req);
return CommonResult.success(res);
} }
} }

View File

@@ -226,8 +226,6 @@ public class ProductionPlanServiceImpl implements ProductionPlanService {
@Override @Override
public int getGrowingPlotCount(String baseId) { public int getGrowingPlotCount(String baseId) {
List<ProductionPlanDO> planList = productionPlanMapper.selectList("base_id", baseId); List<ProductionPlanDO> planList = productionPlanMapper.selectList("base_id", baseId);
long count = planList.stream().filter(e -> Objects.equals(e.getPlanStatus(), PLAN_STATUS_2)).count(); long count = planList.stream().filter(e -> Objects.equals(e.getPlanStatus(), PLAN_STATUS_2)).count();
return (int) count; return (int) count;

View File

@@ -1,6 +1,10 @@
package cn.iocoder.yudao.module.farm.utils; package cn.iocoder.yudao.module.farm.utils;
import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
/** /**
* @description: * @description:
@@ -9,9 +13,23 @@ import java.time.LocalDate;
*/ */
public class DateUtils { public class DateUtils {
private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static boolean isTodayInRange(LocalDate startDate, LocalDate endDate) { public static boolean isTodayInRange(LocalDate startDate, LocalDate endDate) {
LocalDate today = LocalDate.now(); LocalDate today = LocalDate.now();
return !today.isBefore(startDate) && !today.isAfter(endDate); return !today.isBefore(startDate) && !today.isAfter(endDate);
} }
/**
* 将时间戳转换为LocalDateTime
* @param timestamp 时间戳(毫秒)
* @return LocalDateTime对象
*/
public static LocalDateTime timestampToLocalDateTime(long timestamp) {
return LocalDateTime.ofInstant(
Instant.ofEpochMilli(timestamp),
ZoneId.systemDefault()
);
}
} }

View File

@@ -29,4 +29,13 @@
</where> </where>
</select> </select>
<select id="countDeviceState" resultType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.DeviceStateRespVO">
SELECT
COUNT(*) as totalDevices,
SUM(CASE WHEN device_state = 1 THEN 1 ELSE 0 END) as totalOnlineDevices,
SUM(CASE WHEN device_state != 1 THEN 1 ELSE 0 END) as totalOfflineDevices
FROM farm_device_info
WHERE tenant_id = #{tenantId} AND deleted = b'0'
</select>
</mapper> </mapper>

View File

@@ -9,4 +9,19 @@
文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/
--> -->
<select id="getFarmingDistributionChart"
parameterType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmingDistributionReqVO"
resultType="cn.iocoder.yudao.module.farm.controller.admin.api.vo.FarmingDistributionRespVO">
SELECT
COUNT(*) as totalCount,
SUM(CASE WHEN task_status = 0 THEN 1 ELSE 0 END) as notStart,
SUM(CASE WHEN task_status = 1 THEN 1 ELSE 0 END) as executingStatusCount,
SUM(CASE WHEN task_status = 2 THEN 1 ELSE 0 END) as completedStatusCount
FROM farm_farming_record
<where>
del_status = 0
<if test="baseId != null and baseId != ''">AND base_id = #{baseId}</if>
<if test="tenantId != null and tenantId != ''">AND tenant_id = #{tenantId}</if>
</where>
</select>
</mapper> </mapper>