feat (farm): 微信端-设备列表 , PC端扫描二维码

-
This commit is contained in:
达富斌
2025-09-27 20:01:18 +08:00
parent 05b4b8f088
commit 8157457de3
25 changed files with 128 additions and 945 deletions

View File

@@ -155,9 +155,9 @@ public class WxController {
target.setBindingStateName(BINDING_STATE_MAP.get(e.getBindingState())); target.setBindingStateName(BINDING_STATE_MAP.get(e.getBindingState()));
target.setDevicePoint(e.getPoint()); target.setDevicePoint(e.getPoint());
// TODO: 2025/9/26 接入真实数据 // TODO: 2025/9/26 接入真实数据
target.setRealData(Arrays.asList(new DeviceInfoRespVO.DeviceRealData("剩余电量", 100), target.setRealData(Arrays.asList(new DeviceInfoRespVO.DeviceRealData("剩余电量", 100,"%"),
new DeviceInfoRespVO.DeviceRealData("大气湿度", 0), new DeviceInfoRespVO.DeviceRealData("大气湿度", 0, "%HR"),
new DeviceInfoRespVO.DeviceRealData("大气温度", 0) new DeviceInfoRespVO.DeviceRealData("大气温度", 0, "℃")
)); ));
return target; return target;
}).toList(); }).toList();

View File

@@ -90,6 +90,7 @@ public class DeviceInfoRespVO {
public static class DeviceRealData{ public static class DeviceRealData{
private String k1; private String k1;
private Integer v1; private Integer v1;
private String u1;
} }
} }

View File

@@ -1,204 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil;
import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.UserLoginRespVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: 缓存token
* @author: binda
* @date: 2025/9/17 14:33
*/
@Slf4j
public abstract class BaseTokenCacheService {
// 使用ConcurrentHashMap存储token信息,key: tenantId, value: token
private final Map<String, String> tokenCache = new ConcurrentHashMap<>();
// 存储token详细信息,key: token, value: UserLoginRespVO
private final Map<String, UserLoginRespVO> tokenDetailCache = new ConcurrentHashMap<>();
/**
* 每30分钟清理一次过期token
*/
@Scheduled(fixedRate = 30 * 60 * 1000) // 30分钟,单位毫秒
public void cleanExpiredTokens() {
long currentTime = System.currentTimeMillis() / 1000;
int initialTokenCount = tokenDetailCache.size();
int initialTenantCount = tokenCache.size();
// 清理过期的token详情
tokenDetailCache.entrySet().removeIf(entry ->
entry.getValue() != null && entry.getValue().expDate <= currentTime
);
// 同步清理租户ID映射
tokenCache.entrySet().removeIf(entry -> {
String token = entry.getValue();
UserLoginRespVO tokenInfo = tokenDetailCache.get(token);
return tokenInfo == null || tokenInfo.expDate <= currentTime;
});
int finalTokenCount = tokenDetailCache.size();
int finalTenantCount = tokenCache.size();
int removedTokenCount = initialTokenCount - finalTokenCount;
int removedTenantCount = initialTenantCount - finalTenantCount;
log.info("Token缓存清理完成: 清理前 {} 个token({} 租户), 清理后 {} 个token({} 租户), 移除 {} 个过期token({} 租户)",
initialTokenCount, initialTenantCount,
finalTokenCount, finalTenantCount,
removedTokenCount, removedTenantCount);
}
/**
* 缓存token(基于租户ID)
*/
protected void cacheToken(String tenantId, UserLoginRespVO loginRespVO) {
if (tenantId != null && loginRespVO != null && loginRespVO.token != null) {
// 存储租户ID到token的映射
tokenCache.put(tenantId, loginRespVO.token);
// 存储token详细信息
tokenDetailCache.put(loginRespVO.token, loginRespVO);
log.debug("租户 {} 的Token已缓存: {}", tenantId, loginRespVO.token);
}
}
protected void cacheToken(String tenantId, String token) {
tokenCache.put(tenantId, token);
}
/**
* 根据租户ID获取token
*/
protected String getTokenByTenantId(String tenantId) {
String token = tokenCache.get(tenantId);
if (token != null && isTokenValid(token)) {
log.debug("获取租户 {} 的Token: {}", tenantId, token);
return token;
}
// 如果token过期,移除映射
if (token != null) {
tokenCache.remove(tenantId);
tokenDetailCache.remove(token);
log.debug("租户 {} 的Token已过期,已移除", tenantId);
}
return null;
}
/**
* 根据租户ID获取token详细信息
*/
protected UserLoginRespVO getTokenInfoByTenantId(String tenantId) {
String token = getTokenByTenantId(tenantId);
if (token != null) {
return tokenDetailCache.get(token);
}
return null;
}
/**
* 根据token获取详细信息
*/
protected UserLoginRespVO getTokenInfo(String token) {
UserLoginRespVO tokenInfo = tokenDetailCache.get(token);
if (tokenInfo != null && isTokenValid(tokenInfo)) {
return tokenInfo;
}
// 如果token过期,移除
if (tokenInfo != null) {
removeTokenByValue(token);
}
return null;
}
/**
* 检查租户的token是否有效
*/
protected boolean isTokenValidByTenantId(String tenantId) {
String token = tokenCache.get(tenantId);
boolean isValid = token != null && isTokenValid(token);
log.debug("租户 {} 的Token验证结果: {}", tenantId, isValid ? "有效" : "无效");
return isValid;
}
/**
* 检查token是否有效
*/
protected boolean isTokenValid(String token) {
UserLoginRespVO tokenInfo = tokenDetailCache.get(token);
boolean isValid = tokenInfo != null && isTokenValid(tokenInfo);
log.debug("Token验证结果: {} -> {}", token, isValid ? "有效" : "无效");
return isValid;
}
/**
* 检查token是否有效(内部方法)
*/
private boolean isTokenValid(UserLoginRespVO tokenInfo) {
long currentTime = System.currentTimeMillis() / 1000;
return tokenInfo.expDate > currentTime;
}
/**
* 根据租户ID移除token
*/
protected void removeTokenByTenantId(String tenantId) {
String token = tokenCache.remove(tenantId);
if (token != null) {
tokenDetailCache.remove(token);
log.debug("租户 {} 的Token已移除: {}", tenantId, token);
}
}
/**
* 根据token值移除
*/
protected void removeTokenByValue(String token) {
// 需要找到对应的租户ID
tokenDetailCache.remove(token);
tokenCache.entrySet().removeIf(entry -> entry.getValue().equals(token));
log.debug("Token已移除: {}", token);
}
/**
* 获取所有租户的token数量
*/
protected int getTenantTokenCount() {
return tokenCache.size();
}
/**
* 获取所有token的数量
*/
protected int getTotalTokenCount() {
return tokenDetailCache.size();
}
/**
* 清理所有token
*/
protected void clearAllTokens() {
int tenantCount = tokenCache.size();
int tokenCount = tokenDetailCache.size();
tokenCache.clear();
tokenDetailCache.clear();
log.info("所有Token已清除,共清除 {} 个租户的 {} 个token", tenantCount, tokenCount);
}
/**
* 获取租户ID列表
*/
protected java.util.Set<String> getAllTenantIds() {
return new java.util.HashSet<>(tokenCache.keySet());
}
/**
* 获取所有token信息(调试用)
*/
protected Map<String, String> getTokenCache() {
return new ConcurrentHashMap<>(tokenCache);
}
}

View File

@@ -1,186 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil;
/**
* @description: 土壤墒情
* @author: binda
* @date: 2025/9/17 10:57
*/
//@Service
public class SoilService extends BaseTokenCacheService {
//
// private final DeviceConf deviceConf;
// private final HttpClientUtils httpClientUtils;
//
// public SoilService(DeviceConf deviceConf, HttpClientUtils httpClientUtils) {
// this.deviceConf = deviceConf;
// this.httpClientUtils = httpClientUtils;
// }
//
// private final String SOIL = "soil_";
//
// public void userLogin() {
// String username = deviceConf.getFourSituations().getUsername();
// String password = deviceConf.getFourSituations().getPassword();
//
// this.userLogin(new UserLoginReqVO(username,password));
// }
//
// /**
// * 登录获取token
// *
// * @param req
// * @return
// */
// public UserLoginRespVO userLogin(UserLoginReqVO req) {
// String tenantId = getLoginUser().getTenantId().toString();
// String hosts = deviceConf.getFourSituations().getHosts();
// String userLoginURL = deviceConf.getFourSituations().getGlobal().getUrl21();
//
// try {
// ApiResponse<UserLoginRespVO> response = httpClientUtils.postRequest(hosts, userLoginURL, req, null, UserLoginRespVO.class);
//
// if (response.isSuccess()) {
// UserLoginRespVO data = response.getData();
// // TODO: 2025/9/17 持久化
// cacheToken(SOIL+tenantId, data);
// }
//
// return response.getData();
// } catch (Exception e) {
// log.error("租户 {} 登录失败: {}", tenantId, e.getMessage(), e);
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_USER_LOGIN);
// }
// }
//
// /**
// * 验证租户token有效性
// */
// public boolean validateUserToken(String tenantId) {
// log.debug("验证租户 {} 的Token", tenantId);
// return isTokenValidByTenantId(SOIL+tenantId);
// }
//
// /**
// * 获取用户设备
// */
// public List<SysUserDeviceRespVO> getSysUserDevice(SysUserDeviceReqVO req) {
//
// String tenantId = getLoginUser().getTenantId().toString();
// String token = getTokenByTenantId(tenantId);
// String hosts = deviceConf.getFourSituations().getHosts();
// String getSysUserDeviceURL = deviceConf.getFourSituations().getGlobal().getUrl26();
//
// Map<String, String> headers = new HashMap<>();
// headers.put("token", token);
//
// Map<String, String> params = new HashMap<>();
// params.put("groupId", StringUtils.defaultString(req.getGroupId()));
// params.put("deviceType", StringUtils.defaultString(req.getDeviceType()));
//
// try {
//
// ApiResponse<List<SysUserDeviceRespVO>> response = httpClientUtils.getRequestAsList(hosts, getSysUserDeviceURL, params, headers, SysUserDeviceRespVO.class);
// if (!response.isSuccess()) {
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_USER_DEVICE);
// }
// return response.getData();
// } catch (Exception e) {
// e.printStackTrace();
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_USER_DEVICE);
// }
//
// }
//
// /**
// * 获取设备实时数据
// */
// public List<RealTimeDataRespVO> getRealTimeData(RealTimeDataReqVO req) {
// String tenantId = getLoginUser().getTenantId().toString();
// String token = getTokenByTenantId(tenantId);
// String hosts = deviceConf.getFourSituations().getHosts();
// String getSysUserDeviceURL = deviceConf.getFourSituations().getGlobal().getUrl27();
//
// Map<String, String> headers = new HashMap<>();
// headers.put("token", token);
// Map<String, String> params = new HashMap<>();
// params.put("deviceAddrs", req.getDeviceAddrs());
//
// try {
// ApiResponse<List<RealTimeDataRespVO>> response = httpClientUtils.getRequestAsList(hosts, getSysUserDeviceURL, params, headers, RealTimeDataRespVO.class);
// if (!response.isSuccess()) {
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_REAL_TIME_DATA);
// }
// return response.getData();
// } catch (Exception e) {
// e.printStackTrace();
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_REAL_TIME_DATA);
// }
//
// }
//
// /**
// * 设备报警通知记录
// */
// public List<AlarmNoticeRecordRespVO> getAlarmNoticeRecord(AlarmNoticeRecordReqVO req) {
//
// String tenantId = getLoginUser().getTenantId().toString();
// String token = getTokenByTenantId(tenantId);
// String hosts = deviceConf.getFourSituations().getHosts();
// String getAlarmNoticeRecord = deviceConf.getFourSituations().getGlobal().getUrl24();
//
// Map<String, String> headers = new HashMap<>();
// headers.put("token", token);
// Map<String, String> params = req.toFieldValueMap();
//
// try {
// ApiResponse<List<AlarmNoticeRecordRespVO>> response = httpClientUtils.getRequestAsList(hosts, getAlarmNoticeRecord, params, headers, AlarmNoticeRecordRespVO.class);
// if (!response.isSuccess()) {
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_ALARM_NOTICE_RECORD);
// }
// return response.getData();
// } catch (Exception e) {
// e.printStackTrace();
// throw exception(DEVICE_INFO_NOT_EXISTS_FOR_ALARM_NOTICE_RECORD);
// }
//
// }
//
// /**
// * 墒情设备, 获取设备全部信息
// */
// public List<DeviceAllInfoRespVO> getDeviceAllInfo(DeviceAllInfoReqVO req) {
//
//
// return null;
// }
//
// /**
// * 墒情设备, 更新设备信息
// */
// public Boolean updateDevice(UpdateDeviceReqVO req) {
//
//
// return false;
// }
//
// /**
// * 墒情设备, 更新节点信息
// */
// public Boolean updateNodeInfo(UpdateNodeInfoReqVO req) {
//
//
// return false;
// }
//
// /**
// * 墒情设备, 获取历史数据
// */
// public HistoryDataListPageRespVO getHistoryDataList(HistoryDataListPageReqVO req) {
//
//
//
// return null;
// }
}

View File

@@ -1,109 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
/**
* @description: 墒情设备, 获取历史数据 请求实体
* @author: binda
* @date: 2025/9/17 20:53
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HistoryDataListPageReqVO {
/**
* 必选
* 开始时间 (时间戳)
*/
private String beginTime;
/**
* 必选
* 结束时间 (时间戳)
*/
private String endTime;
/**
* 必选
* 设备地址
*/
private String deviceAddr;
/**
* 非必选
* 节点ID
*/
private String nodeId;
/**
* 必选
* 页码
*/
private Integer pages;
/**
* 必选
* 每页数量
*/
private Integer limit;
public HistoryDataListPageReqVO(String beginTime, String endTime) {
this.beginTime = beginTime;
this.endTime = endTime;
}
public static class HistoryDataTimeRangeUtil {
/**
* 获取近12小时的时间范围
*/
public static HistoryDataListPageReqVO getLast12Hours() {
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusHours(12);
return buildRequestVO(startTime, endTime);
}
/**
* 获取近一天的时间范围
*/
public static HistoryDataListPageReqVO getLast24Hours() {
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusDays(1);
return buildRequestVO(startTime, endTime);
}
/**
* 获取近三天的时间范围
*/
public static HistoryDataListPageReqVO getLast3Days() {
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusDays(3);
return buildRequestVO(startTime, endTime);
}
/**
* 获取近七天的时间范围
*/
public static HistoryDataListPageReqVO getLast7Days() {
LocalDateTime endTime = LocalDateTime.now();
LocalDateTime startTime = endTime.minusDays(7);
return buildRequestVO(startTime, endTime);
}
/**
* 构建请求VO对象
*/
private static HistoryDataListPageReqVO buildRequestVO(LocalDateTime startTime, LocalDateTime endTime) {
String beginTimeStamp = String.valueOf(startTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
String endTimeStamp = String.valueOf(endTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
return new HistoryDataListPageReqVO(beginTimeStamp, endTimeStamp);
}
}
}

View File

@@ -1,62 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @description: 墒情设备, 获取历史数据 响应实体
* @author: binda
* @date: 2025/9/17 20:53
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HistoryDataListPageRespVO {
/**
* 页码,每页数量,总页数,总条数
*/
private Integer pages;
private Integer limit;
private Integer totalPages;
private Integer total;
private List<Row> rows;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Row{
/**
* 记录表 id
*/
private Integer historyId;
/**
* 节点编号
*/
private Integer nodeId;
/**
* 设备地址
*/
private String deviceAddress;
/**
* 模拟量 1
*/
private String temStr;
private Double temValue;
/**
* 模拟狼 2
*/
private String humStr;
private Double humValue;
/**
* 是否是报警数据 0:正常 1:报警
*/
private Integer alarmStatus;
/**
* 保存时间(时间戳)
*/
private Long recordTime;
}
}

View File

@@ -1,23 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @description: 设备实时数据 请求实体
* @author: binda
* @date: 2025/9/17 19:02
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RealTimeDataReqVO {
/**
* 设备地址 非必定
* tips: 多个用英文逗号分隔,空为获取当前用户下的所有设备
*/
private String deviceAddrs;
}

View File

@@ -1,68 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @description: 设备实时数据 相应试题
* @author: binda
* @date: 2025/9/17 19:01
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RealTimeDataRespVO {
/**
* 设备地址
*/
private String deviceAddr;
/**
* 设备名称
*/
private String deviceName;
/**
* 经度
*/
private Double lat;
/**
* 维度
*/
private Double lng;
/**
* 设备状态
*/
private String status;
/**
* 设备类型
*/
private String deviceType;
private List<RealTimeData> data;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class RealTimeData {
// 节点编号
private Integer nodeId;
// 节点名称
private String nodeName;
// 节点类型
private Integer nodeType;
// 模拟量1 名称,单位,原值,显示值,报警等级
private String temName;
private String temUnit;
private Double temValue;
private String temValueStr;
private Integer temAlarmStatus;
// 模拟量2 名称,单位,原值,显示值,报警等级
private String humName;
private String humUnit;
private String humValue;
private String humValueStr;
private String humAlarmStatus;
}
}

View File

@@ -1,24 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 获取用户设备 请求实体
* @author: binda
* @date: 2025/9/17 15:28
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysUserDeviceReqVO {
/**
* 区域ID 非必填
*/
private String groupId;
/**
* 设备类型 非必填
*/
private String deviceType;
}

View File

@@ -1,45 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 获取用户设备 响应实体
* @author: binda
* @date: 2025/9/17 15:31
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SysUserDeviceRespVO {
/**
* 设备地址
*/
public String deviceAddr;
/**
* 区域ID
*/
public String groupId;
/**
* 设备类型
*/
public String deviceType;
/**
* 设备名称
*/
public String deviceName;
/**
* 设备的经度
*/
public String deviceLng;
/**
* 设备的维度
*/
public String deviceLat;
/**
* 设备iccid
*/
public String deviceIccId;
}

View File

@@ -1,18 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 登录请求实体
* @author: binda
* @date: 2025/9/17 13:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserLoginReqVO {
public String loginName;
public String loginPwd;
}

View File

@@ -1,32 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 登录响应实体
* @author: binda
* @date: 2025/9/17 13:46
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserLoginRespVO {
/**
* 登录标识
*/
public String loginSign;
/**
* token 生成时间
*/
public long currDate;
/**
* 过期时间
*/
public long expDate;
/**
* 令牌
*/
public String token;
}

View File

@@ -1,24 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.wf.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description:
* @author: binda
* @date: 2025/9/25 23:07
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DevicePageReqVO {
/**
* 令牌 必填
*/
private String token;
/**
* 用户名
*/
private String userCode;
}

View File

@@ -1,51 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.wf.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
import java.util.List;
/**
* @description: 获取设备列表 分页响应实体
* @author: binda
* @date: 2025/9/18 14:30
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DevicePageRespVO {
private Integer code;
private String msg;
private Integer total;
private List<Row> rows;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Row{
private Long deviceId;
private Long deptId;
private String productCode;
private String productName;
private String modelCode;
private String deviceCode;
private String code; // 设备编号
private String name;
private String farmland;
private String modelName;
private String userCode;
private Double lng;
private Double lat;
private Long farmlandId;
private String delFlag;
private String loginIp;
private Date loginDate;
private String createBy;
private Date createTime;
private String updateBy;
private Date updateTime;
private String remark;
}
}

View File

@@ -1,18 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.wf.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 获取公钥 请求实体
* @author: binda
* @date: 2025/9/18 14:19
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginReqVO {
private String username;
private String password;
}

View File

@@ -1,19 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.wf.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 获取公钥 响应实体
* @author: binda
* @date: 2025/9/18 14:26
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginRespVO {
private Integer code;
private String msg;
private String token;
}

View File

@@ -1,35 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.wf.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @description: 设备实时数据
* @author: binda
* @date: 2025/9/18 14:38
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RealTimeDeviceDataRespVO {
private String deviceId;
private String name;
private String stateText; // 是否在线 中文
private String stateValue; // 是否在线 编码 online
private List<ControlProperty> controlProperties;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class ControlProperty {
private String id; // 开关标识
private String name;
private String operateType; // 设备类型
private String operateValue;
private String value;
private String formatValue;
}
}

View File

@@ -1,18 +0,0 @@
package cn.iocoder.yudao.module.farm.manager.devices.wf.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @description: 更改设备属性 响应实体
* @author: binda
* @date: 2025/9/18 14:45
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UpdateDeviceStatusRespVO {
private Integer code;
private String msg;
}

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; package cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; package cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; package cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; package cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; package cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil.notice;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; package cn.iocoder.yudao.module.farm.manager.equipmentproducer.dto.soil.notice;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;

View File

@@ -0,0 +1,118 @@
package cn.iocoder.yudao.module.farm.manager.equipmentproducer.utils;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.Map;
/**
* @description:
* @author: binda
* @date: 2025/9/27 19:38
*/
@Component
public class HttpClientUtils {
private final RestTemplate restTemplate;
public HttpClientUtils(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
/**
* GET请求
*/
public <T> T doGet(String url, Map<String, String> headers, Map<String, Object> params, Class<T> responseType) {
try {
// 设置请求头
HttpHeaders httpHeaders = new HttpHeaders();
if (headers != null) {
headers.forEach(httpHeaders::set);
}
// 构建查询参数
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
if (params != null) {
params.forEach((key, value) -> {
if (value != null) {
builder.queryParam(key, value.toString());
}
});
}
HttpEntity<String> entity = new HttpEntity<>(httpHeaders);
ResponseEntity<T> response = restTemplate.exchange(
builder.build().toUri(),
HttpMethod.GET,
entity,
responseType
);
return response.getBody();
} catch (Exception e) {
throw new RuntimeException("HTTP GET请求失败: " + e.getMessage(), e);
}
}
/**
* POST请求 - JSON格式
*/
public <T> T doPost(String url, Map<String, String> headers, Object requestBody, Class<T> responseType) {
try {
// 设置请求头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
if (headers != null) {
headers.forEach(httpHeaders::set);
}
HttpEntity<Object> entity = new HttpEntity<>(requestBody, httpHeaders);
ResponseEntity<T> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
responseType
);
return response.getBody();
} catch (Exception e) {
throw new RuntimeException("HTTP POST请求失败: " + e.getMessage(), e);
}
}
/**
* POST请求 - 表单格式
*/
public <T> T doPostForm(String url, Map<String, String> headers, Map<String, String> formData, Class<T> responseType) {
try {
// 设置请求头
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
if (headers != null) {
headers.forEach(httpHeaders::set);
}
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
if (formData != null) {
formData.forEach(body::add);
}
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(body, httpHeaders);
ResponseEntity<T> response = restTemplate.exchange(
url,
HttpMethod.POST,
entity,
responseType
);
return response.getBody();
} catch (Exception e) {
throw new RuntimeException("HTTP POST表单请求失败: " + e.getMessage(), e);
}
}
}