Compare commits
3 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
7adbe19a7d | |
|
|
c609b06781 | |
|
|
c297d418da |
|
|
@ -12,14 +12,10 @@ COPY agri-admin.jar /app/agri-admin.jar
|
|||
EXPOSE 8088
|
||||
|
||||
# -d 是 docker run 的后台参数,不属于程序启动参数
|
||||
# 固定启动命令主体
|
||||
ENTRYPOINT ["java", "-jar", "/app/agri-admin.jar"]
|
||||
|
||||
# 默认激活的配置文件,可被 docker run 覆盖
|
||||
CMD ["--spring.profiles.active=druid,mqtt,prod"]
|
||||
ENTRYPOINT ["java","-jar","/app/agri-admin.jar"]
|
||||
|
||||
# 声明容器对外暴露端口(只是声明,真正映射端口靠 docker run -p)
|
||||
# EXPOSE 8088 5005
|
||||
|
||||
# -d 是 docker run 的后台参数,不属于程序启动参数
|
||||
# ENTRYPOINT ["java","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005","-jar","/app/agri-admin.jar", "--spring.profiles.active=druid,mqtt,prod"]
|
||||
# ENTRYPOINT ["java","-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005","-jar","/app/agri-admin.jar"]
|
||||
|
|
|
|||
104
README.md
104
README.md
|
|
@ -1,15 +1,95 @@
|
|||
# MQTT 压测脚本说明
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Agri v3.9.0</h1>
|
||||
<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/y_project/Agri-Vue/stargazers"><img src="https://gitee.com/y_project/Agri-Vue/badge/star.svg?theme=dark"></a>
|
||||
<a href="https://gitee.com/y_project/Agri-Vue"><img src="https://img.shields.io/badge/Agri-v3.9.0-brightgreen.svg"></a>
|
||||
<a href="https://gitee.com/y_project/Agri-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
|
||||
</p>
|
||||
|
||||
## 脚本列表
|
||||
- pressure_up.sh:设备状态上报压测
|
||||
- pressure_mix.sh:上报 + 控制混合压测
|
||||
## 平台简介
|
||||
|
||||
## 使用说明
|
||||
1. 安装 mosquitto-clients
|
||||
2. 修改脚本中的 BROKER / IMEI 范围
|
||||
3. chmod +x *.sh
|
||||
4. 运行脚本
|
||||
智能农业是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
|
||||
|
||||
## 停止压测
|
||||
```bash
|
||||
pkill mosquitto_pub
|
||||
* 前端采用Vue、Element UI。
|
||||
* 后端采用Spring Boot、Spring Security、Redis & Jwt。
|
||||
* 权限认证使用Jwt,支持多终端认证系统。
|
||||
* 支持加载动态权限菜单,多方式轻松权限控制。
|
||||
* 高效率开发,使用代码生成器可以一键生成前后端代码。
|
||||
* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
|
||||
* 提供了单应用版本[RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast),Oracle版本[RuoYi-Vue-Oracle](https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
|
||||
* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
|
||||
* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)
|
||||
|
||||
## 内置功能
|
||||
|
||||
1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
|
||||
2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
|
||||
3. 岗位管理:配置系统用户所属担任职务。
|
||||
4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
|
||||
5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
|
||||
6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
|
||||
7. 参数管理:对系统动态配置常用参数。
|
||||
8. 通知公告:系统通知公告信息发布维护。
|
||||
9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
|
||||
10. 登录日志:系统登录日志记录查询包含登录异常。
|
||||
11. 在线用户:当前系统中活跃用户状态监控。
|
||||
12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
|
||||
13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
|
||||
14. 系统接口:根据业务代码自动生成相关的api接口文档。
|
||||
15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
|
||||
16. 缓存监控:对系统的缓存信息查询,命令统计等。
|
||||
17. 在线构建器:拖动表单元素生成相应的HTML代码。
|
||||
18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
|
||||
|
||||
## 在线体验
|
||||
|
||||
- admin/admin123
|
||||
- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
|
||||
|
||||
演示地址:http://vue.ruoyi.vip
|
||||
文档地址:http://doc.ruoyi.vip
|
||||
|
||||
## 演示图
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
|
||||
<td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## 智能农业前后端分离交流群
|
||||
|
||||
QQ群: [](https://jq.qq.com/?_wv=1027&k=5bVB1og) [](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [](https://jq.qq.com/?_wv=1027&k=51G72yr) [](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [](https://jq.qq.com/?_wv=1027&k=SpyH2875) [](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=GsOo-OLz53J8y_9TPoO6XXSGNRTgbFxA&authKey=R7Uy%2Feq%2BZsoKNqHvRKhiXpypW7DAogoWapOawUGHokJSBIBIre2%2FoiAZeZBSLuBc&noverify=0&group_code=191164766) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=PmYavuzsOthVqfdAPbo4uAeIbu7Ttjgc&authKey=p52l8%2FXa4PS1JcEmS3VccKSwOPJUZ1ZfQ69MEKzbrooNUljRtlKjvsXf04bxNp3G&noverify=0&group_code=174569686) 点击按钮入群。
|
||||
|
|
@ -3,15 +3,16 @@ package com.agri.web.controller.mqtt;
|
|||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.framework.manager.AgriStatusManager;
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.framework.manager.MqttClientManager;
|
||||
import com.agri.framework.manager.MqttSubscriptionManager;
|
||||
import com.agri.framework.interceptor.MqttMessageHandler;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
|
@ -26,15 +27,7 @@ public class MqttController {
|
|||
private static final Logger log = LoggerFactory.getLogger(MqttController.class);
|
||||
|
||||
@Resource
|
||||
private MqttSubscriptionManager mqttSubscriptionManager;
|
||||
@Resource
|
||||
private MqttClientManager mqttClientManager;
|
||||
|
||||
@Autowired
|
||||
private MqttAutoOffManager mqttAutoOffManager;
|
||||
|
||||
@Autowired
|
||||
private AgriStatusManager agriStatusManager;
|
||||
private MqttMessageHandler mqttMessageHandler;
|
||||
|
||||
/**
|
||||
* 单个订阅
|
||||
|
|
@ -43,7 +36,7 @@ public class MqttController {
|
|||
@Log(title = "订阅主题", businessType = BusinessType.INSERT)
|
||||
public String subscribe(@RequestParam String clientId, @RequestParam String deviceId) {
|
||||
try {
|
||||
mqttSubscriptionManager.subscribeDevice(clientId, deviceId);
|
||||
mqttMessageHandler.subscribeDevice(clientId, deviceId);
|
||||
return "订阅成功";
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("MQTT单个订阅失败:{}", e.getMessage());
|
||||
|
|
@ -60,7 +53,7 @@ public class MqttController {
|
|||
@DeleteMapping("/single")
|
||||
public String unsubscribe(@RequestParam String clientId, @RequestParam String deviceId) {
|
||||
try {
|
||||
mqttSubscriptionManager.unsubscribeDevice(clientId, deviceId);
|
||||
mqttMessageHandler.unsubscribeDevice(clientId, deviceId);
|
||||
return "取消订阅成功";
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("MQTT单个取消订阅失败:{}", e.getMessage());
|
||||
|
|
@ -79,7 +72,7 @@ public class MqttController {
|
|||
public AjaxResult subscribeAll(@RequestParam String clientId) {
|
||||
try {
|
||||
// 返回前端需要取消的MQTT主题列表
|
||||
return AjaxResult.success(mqttSubscriptionManager.subscribeAllDeviceByUserId(clientId));
|
||||
return AjaxResult.success(mqttMessageHandler.subscribeAllDeviceByUserId(clientId));
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("MQTT批量订阅失败:{}", e.getMessage());
|
||||
// 异常时返回空列表,避免前端解析失败
|
||||
|
|
@ -98,7 +91,7 @@ public class MqttController {
|
|||
public List<String> unsubscribeAll(@RequestParam String clientId) {
|
||||
try {
|
||||
// 返回前端需要取消的MQTT主题列表
|
||||
return mqttSubscriptionManager.unsubscribeAllDevice(clientId);
|
||||
return mqttMessageHandler.unsubscribeAllDevice(clientId);
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("MQTT批量取消订阅失败:{}", e.getMessage());
|
||||
// 异常时返回空列表,避免前端解析失败
|
||||
|
|
@ -116,7 +109,7 @@ public class MqttController {
|
|||
@Log(title = "手动触发MQTT重连", businessType = BusinessType.OTHER)
|
||||
public String manualReconnect() {
|
||||
try {
|
||||
return mqttClientManager.manualReconnect();
|
||||
return mqttMessageHandler.manualReconnect();
|
||||
} catch (Exception e) {
|
||||
log.error("MQTT手动重连异常", e);
|
||||
return "手动重连失败:" + e.getMessage();
|
||||
|
|
@ -128,32 +121,13 @@ public class MqttController {
|
|||
* 便于排查连接问题
|
||||
*/
|
||||
@GetMapping("/status")
|
||||
public AjaxResult getMqttStatus() {
|
||||
@Log(title = "手动触发MQTT重连", businessType = BusinessType.SELECT)
|
||||
public String getMqttStatus() {
|
||||
try {
|
||||
return AjaxResult.success(mqttClientManager.getMqttStatus());
|
||||
return mqttMessageHandler.getMqttStatus();
|
||||
} catch (Exception e) {
|
||||
log.error("查询MQTT连接状态异常", e);
|
||||
return AjaxResult.error("查询状态失败:" + e.getMessage());
|
||||
return "查询状态失败:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 2️⃣ 查询某个设备是否存在自动关任务
|
||||
*/
|
||||
@GetMapping("/device/{deviceId}")
|
||||
public AjaxResult device(@PathVariable String deviceId) {
|
||||
boolean hasTask = mqttAutoOffManager.hasAutoOffTask(deviceId);
|
||||
return AjaxResult.success(hasTask);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/getAgriStatus")
|
||||
public void getAgriStatus(@RequestBody List<String> imeiList) {
|
||||
|
||||
if (imeiList.isEmpty()) {
|
||||
log.info("大棚表无数据,结束推送");
|
||||
return;
|
||||
}
|
||||
agriStatusManager.asyncBatchPushMqtt(agriStatusManager.batchCheckDeviceOnline(imeiList));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,8 @@
|
|||
package com.agri.web.controller.tool;
|
||||
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.core.domain.R;
|
||||
import com.agri.common.utils.StringUtils;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
|
||||
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
|
||||
import io.swagger.annotations.Api;
|
||||
|
|
@ -13,7 +11,6 @@ import io.swagger.annotations.ApiImplicitParams;
|
|||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
|
@ -23,7 +20,6 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
|
|
@ -41,9 +37,6 @@ import java.util.Map;
|
|||
@RequestMapping("/test/user")
|
||||
public class TestController extends BaseController
|
||||
{
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
|
||||
{
|
||||
users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
|
||||
|
|
@ -125,16 +118,6 @@ public class TestController extends BaseController
|
|||
return R.fail("用户不存在");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("getStatus")
|
||||
public void getStatus() throws MqttException {
|
||||
|
||||
|
||||
mqttMessageSender.publish("dtu/864865085008135/down", "{\"jbk\":0,\"read\":true}");
|
||||
logger.info("{\"jbk\":0,\"read\":true}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ApiModel(value = "UserEntity", description = "用户实体")
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.agri: debug
|
||||
org.springframework: warn
|
||||
|
||||
agri:
|
||||
manager:
|
||||
num: 5
|
||||
|
|
@ -6,7 +6,7 @@ spring:
|
|||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://49.233.181.63:3306/agri?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
url: jdbc:mysql://122.51.109.52:3306/agri?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
|
||||
username: root
|
||||
password: lld123
|
||||
# 从库数据源
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
spring:
|
||||
# MQTT配置
|
||||
mqtt:
|
||||
host: tcp://mq.xiaoces.com:1883 # 设备/后端的MQTT TCP地址
|
||||
host: tcp://122.51.109.52:1883 # 设备/后端的MQTT TCP地址
|
||||
username: admin # Mosquitto共用账号
|
||||
password: Admin#12345678 # Mosquitto密码
|
||||
client-id: springboot-backend # 截取UUID前8位(自动去横线)
|
||||
# 后端监听的主题
|
||||
default-topic: dtu/+/up,dtu/+/ack,frontend/+/control/+,frontend/+/online, frontend/+/+/config
|
||||
default-topic: dtu/+/up,frontend/+/control/+,frontend/+/online # 后端监听的主题
|
||||
qos: 0 # 消息可靠性
|
||||
timeout: 60 # 连接超时
|
||||
keep-alive: 60 # 心跳间隔
|
||||
latest-ttl-seconds: 120 #设备最新状态缓存的过期时间(秒)。
|
||||
# 自动关闭任务线程池大小
|
||||
auto-off-thread-pool-size: 5
|
||||
subc-ttl-seconds: 3600 # 在线新跳ttl
|
||||
dtu-ctl-lock-ttl: 20
|
||||
subc-ttl-seconds: 3600 # 在线新跳ttl
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.agri: info
|
||||
org.springframework: warn
|
||||
|
||||
# 大棚管理者
|
||||
agri:
|
||||
manager:
|
||||
num: 5
|
||||
|
|
@ -6,16 +6,12 @@ agri:
|
|||
version: 3.9.0
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/agri/uploadPath,Linux配置 /opt/agri/uploadPath)
|
||||
profile: /opt/agri/uploadPath
|
||||
# 文件路径 示例( Windows配置D:/agri/uploadPath,Linux配置 /home/agri/uploadPath)
|
||||
profile: D:/agri/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: true
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
# 卷膜滚轴长度和秒数
|
||||
per-lap:
|
||||
sec: 18 # 以秒为单位
|
||||
len: 2.13 # 以cm为单位
|
||||
# 开启增强
|
||||
knife4j:
|
||||
enable: true
|
||||
|
|
@ -44,6 +40,12 @@ server:
|
|||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.agri: debug
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
|
|
@ -59,7 +61,7 @@ spring:
|
|||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
active: druid,mqtt,dev
|
||||
active: druid,mqtt
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
|
|
@ -77,7 +79,7 @@ spring:
|
|||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: 49.233.181.63
|
||||
host: 122.51.109.52
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
|
|
|
|||
|
|
@ -16,12 +16,7 @@
|
|||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 工具类 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.20</version> <!-- 该版本完全兼容JDK 8 -->
|
||||
</dependency>
|
||||
|
||||
<!-- Spring框架基本的核心工具 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package com.agri.common.constant;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Locale;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
/**
|
||||
* 通用常量信息
|
||||
|
|
@ -172,11 +170,4 @@ public class Constants
|
|||
*/
|
||||
public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
|
||||
"org.springframework", "org.apache", "com.agri.common.utils.file", "com.agri.common.config", "com.agri.generator" };
|
||||
|
||||
public static final String JM1G = "jm1g";
|
||||
|
||||
public static final BigDecimal PER_LAP_LEN = BigDecimal.valueOf(2.13);
|
||||
|
||||
public static final BigDecimal PER_LAP_SEC = BigDecimal.valueOf(18);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +1,35 @@
|
|||
package com.agri.common.core.domain.entity;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import javax.validation.constraints.*;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.annotation.Excel.ColumnType;
|
||||
import com.agri.common.annotation.Excel.Type;
|
||||
import com.agri.common.annotation.Excels;
|
||||
import com.agri.common.annotation.Sensitive;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import com.agri.common.enums.DesensitizedType;
|
||||
import com.agri.common.xss.Xss;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户对象 sys_user
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@TableName("sys_user")
|
||||
public class SysUser extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 用户ID */
|
||||
@Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long userId;
|
||||
|
||||
/** 部门ID */
|
||||
@Excel(name = "部门编号", type = Type.IMPORT)
|
||||
private Long deptId;
|
||||
|
||||
/** 用户账号 */
|
||||
@Excel(name = "clientId")
|
||||
private String clientId;
|
||||
|
||||
/** 用户账号 */
|
||||
@Excel(name = "登录名称")
|
||||
private String userName;
|
||||
|
|
@ -97,23 +79,18 @@ public class SysUser extends BaseEntity
|
|||
@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
|
||||
@Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
|
||||
})
|
||||
@TableField(exist = false)
|
||||
private SysDept dept;
|
||||
|
||||
/** 角色对象 */
|
||||
@TableField(exist = false)
|
||||
private List<SysRole> roles;
|
||||
|
||||
/** 角色组 */
|
||||
@TableField(exist = false)
|
||||
private Long[] roleIds;
|
||||
|
||||
/** 岗位组 */
|
||||
@TableField(exist = false)
|
||||
private Long[] postIds;
|
||||
|
||||
/** 角色ID */
|
||||
@TableField(exist = false)
|
||||
private Long roleId;
|
||||
|
||||
public SysUser()
|
||||
|
|
@ -121,15 +98,6 @@ public class SysUser extends BaseEntity
|
|||
|
||||
}
|
||||
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public SysUser(Long userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
|
|
@ -349,7 +317,6 @@ public class SysUser extends BaseEntity
|
|||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("userId", getUserId())
|
||||
.append("deptId", getDeptId())
|
||||
.append("clientId", getClientId())
|
||||
.append("userName", getUserName())
|
||||
.append("nickName", getNickName())
|
||||
.append("email", getEmail())
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ public class LoginBody
|
|||
* 用户密码
|
||||
*/
|
||||
private String password;
|
||||
private String phonenumber;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
|
|
@ -67,12 +66,4 @@ public class LoginBody
|
|||
{
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String getPhonenumber() {
|
||||
return phonenumber;
|
||||
}
|
||||
|
||||
public void setPhonenumber(String phonenumber) {
|
||||
this.phonenumber = phonenumber;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package com.agri.common.enums;
|
||||
|
||||
public enum AgriEnum {
|
||||
|
||||
|
||||
SCAN(0, "扫码"),
|
||||
INVITE(1, "邀请"),
|
||||
OWNER(3, "大棚所有者"),
|
||||
MANUAL(0, "手动模式"),
|
||||
ALARM_CLOSE(0, "告警关闭"),
|
||||
NO_DELETE(0, "未删除"),
|
||||
ENABLED(1, "已生效"),
|
||||
PENDING_ACCEPTANCE(2, "待接受邀请"),
|
||||
WARN(0, "警告"),
|
||||
SUCCESS(1, "成功"),
|
||||
ERROR(2, "失败");
|
||||
|
||||
private final Integer code;
|
||||
private final String desc;
|
||||
AgriEnum(Integer code, String desc)
|
||||
{
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
package com.agri.common.enums;
|
||||
|
||||
/**
|
||||
* 设备功能枚举
|
||||
*/
|
||||
public enum DtuEnum {
|
||||
|
||||
JM1K("jm1k", "卷膜1开"),
|
||||
JM1G("jm1g", "卷膜1关"),
|
||||
JM2K("jm2k", "卷膜2开"),
|
||||
JM2G("jm2g", "卷膜2关"),
|
||||
JM3K("jm3k", "卷膜3开"),
|
||||
JM3G("jm3g", "卷膜3关"),
|
||||
JBK("jbk", "卷被开"),
|
||||
JBG("jbg", "卷被关");
|
||||
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
|
||||
DtuEnum(String code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.agri.common.enums;
|
||||
|
||||
/**
|
||||
* @ClassName TempCommandStatus
|
||||
* @Description TODO
|
||||
* @Author lld
|
||||
* @Date 2026/3/6 2:46
|
||||
* @Version 1.0
|
||||
*/
|
||||
public enum TempCommandStatus {
|
||||
OPEN(1, "下发开指令"),
|
||||
CLOSE(2, "下发关指令"),
|
||||
NO_OPERATE(0, "不操作");
|
||||
|
||||
private final int code;
|
||||
private final String desc;
|
||||
|
||||
TempCommandStatus(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
// 使用:status.getCode() → 1/2/0
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,50 +0,0 @@
|
|||
package com.agri.common.utils;
|
||||
|
||||
/**
|
||||
* @ClassName dd
|
||||
* @Description TODO
|
||||
* @Author lld
|
||||
* @Date 2026/3/6 1:44
|
||||
* @Version 1.0
|
||||
*/
|
||||
|
||||
import com.agri.common.constant.Constants;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
/**
|
||||
* 卷膜时间计算工具类(企业标准写法:单例+常量固化)
|
||||
*/
|
||||
public class RollerTimeCalculator {
|
||||
|
||||
// 私有化构造器,禁止实例化
|
||||
private RollerTimeCalculator() {}
|
||||
|
||||
/**
|
||||
* 计算卷膜运行时间(秒)
|
||||
* @param targetLen 目标长度(cm,前端统一传入)
|
||||
* @return 运行时间(秒)
|
||||
*/
|
||||
public static int calculateRunTime(BigDecimal targetLen) {
|
||||
// 边界处理:长度≤0时返回0
|
||||
if (targetLen == null || targetLen.compareTo(BigDecimal.ZERO)<=0) {
|
||||
return 0;
|
||||
}
|
||||
// 核心公式:时间 = (长度 / 每圈长度) × 每圈时间
|
||||
BigDecimal cycleCount = targetLen.divide(Constants.PER_LAP_LEN,2, RoundingMode.HALF_UP);
|
||||
return cycleCount.multiply(Constants.PER_LAP_SEC).setScale(2, RoundingMode.HALF_UP).intValue(); // 四舍五入取整
|
||||
}
|
||||
|
||||
/**
|
||||
* 进阶:基础参数可配置化(企业进阶方案)
|
||||
* 从配置中心/参数表读取perLapLen、perLapSec,避免硬编码
|
||||
*/
|
||||
/* public static long calculateRunTimeWithConfig(double targetLen, String imei) {
|
||||
// 从配置表/缓存读取该设备的单圈长度、单圈时间(适配不同设备参数差异)
|
||||
Double deviceCmPerCycle = ConfigCache.getVal(imei + "_perLapLen", perLapLen);
|
||||
Long deviceSecPerCycle = ConfigCache.getVal(imei + "_sec_per_cycle", perLapSec);
|
||||
return Math.round(targetLen / deviceCmPerCycle * deviceSecPerCycle);
|
||||
}*/
|
||||
}
|
||||
|
|
@ -1,20 +1,17 @@
|
|||
package com.agri.common.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
import com.agri.common.constant.Constants;
|
||||
import com.agri.common.constant.HttpStatus;
|
||||
import com.agri.common.core.domain.entity.SysRole;
|
||||
import com.agri.common.core.domain.model.LoginUser;
|
||||
import com.agri.common.exception.ServiceException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 安全服务工具类
|
||||
|
|
@ -24,8 +21,6 @@ import java.util.stream.Collectors;
|
|||
public class SecurityUtils
|
||||
{
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SecurityUtils.class);
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
**/
|
||||
|
|
@ -33,11 +28,7 @@ public class SecurityUtils
|
|||
{
|
||||
try
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (loginUser!= null) {
|
||||
return loginUser.getUserId();
|
||||
}
|
||||
return null;
|
||||
return getLoginUser().getUserId();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -67,11 +58,7 @@ public class SecurityUtils
|
|||
{
|
||||
try
|
||||
{
|
||||
LoginUser loginUser = getLoginUser();
|
||||
if (loginUser !=null ) {
|
||||
return loginUser.getUsername();
|
||||
}
|
||||
return null;
|
||||
return getLoginUser().getUsername();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -84,18 +71,14 @@ public class SecurityUtils
|
|||
**/
|
||||
public static LoginUser getLoginUser()
|
||||
{
|
||||
try {
|
||||
Authentication authentication = getAuthentication();
|
||||
if (authentication == null || !(authentication.getPrincipal() instanceof LoginUser)) {
|
||||
return null; // 无用户上下文时返回 null
|
||||
}
|
||||
return (LoginUser) authentication.getPrincipal();
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
log.error("获取用户信息异常: {}", HttpStatus.UNAUTHORIZED);
|
||||
try
|
||||
{
|
||||
return (LoginUser) getAuthentication().getPrincipal();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -131,15 +114,6 @@ public class SecurityUtils
|
|||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前用户是否是管理员
|
||||
*
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isAdmin()
|
||||
{
|
||||
return isAdmin(getUserId());
|
||||
}
|
||||
/**
|
||||
* 是否为管理员
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
package com.agri.common.utils;
|
||||
|
||||
import com.agri.common.enums.TempCommandStatus;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 温度判断工具类
|
||||
*/
|
||||
public class TempJudgeUtil {
|
||||
// 条件参考温度允许的上下误差(抽成常量,后续可配置化)
|
||||
public static final BigDecimal TEMP_ERROR_RANGE = BigDecimal.valueOf(0.5);
|
||||
|
||||
/**
|
||||
* 温度判断核心方法:根据当前温度与参考温度的差值,返回指令状态
|
||||
*
|
||||
* @param currentTemp 当前温度(DTU上报的温度)
|
||||
* @param refTemp 条件参考温度(sys_auto_term的temp字段)
|
||||
* @return 指令状态:OPEN(开)/CLOSE(关)/NO_OPERATE(不操作)
|
||||
*/
|
||||
public static TempCommandStatus judgeTempCommand(BigDecimal currentTemp, BigDecimal refTemp) {
|
||||
// 1. 空值校验(企业级必备,避免NPE)
|
||||
if (currentTemp == null || refTemp == null) {
|
||||
return TempCommandStatus.NO_OPERATE;
|
||||
}
|
||||
|
||||
// 2. 计算当前温度与参考温度的差值(当前温度 - 参考温度)
|
||||
BigDecimal tempDiff = currentTemp.subtract(refTemp);
|
||||
|
||||
// 3. 按规则判断状态
|
||||
if (tempDiff.compareTo(TEMP_ERROR_RANGE) > 0) {
|
||||
// 当前温度 > 参考温度 + 误差 → 下发开指令
|
||||
return TempCommandStatus.OPEN;
|
||||
} else if (tempDiff.compareTo(TEMP_ERROR_RANGE.negate()) < 0) {
|
||||
// 当前温度 < 参考温度 - 误差 → 下发关指令
|
||||
return TempCommandStatus.CLOSE;
|
||||
} else {
|
||||
// 差值在[-误差, +误差]范围内 → 不操作
|
||||
return TempCommandStatus.NO_OPERATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
package com.agri.common.utils;
|
||||
|
||||
/**
|
||||
* @ClassName TimeConvertUtil
|
||||
* @Description TODO
|
||||
* @Author lld
|
||||
* @Date 2026/3/6 2:16
|
||||
* @Version 1.0
|
||||
*/
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class TimeConvertUtil {
|
||||
// 定义常用时间格式(企业级:固化为常量,避免重复创建)
|
||||
public static final DateTimeFormatter DEFAULT_DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* 字符串转LocalDateTime(适配yyyy-MM-dd HH:mm:ss格式)
|
||||
*/
|
||||
public static LocalDateTime strToLocalDateTime(String timeStr) {
|
||||
// 空值/空白校验(企业级必备)
|
||||
if (timeStr == null || timeStr.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
// 标准格式直接解析
|
||||
return LocalDateTime.parse(timeStr.trim(), DEFAULT_DATETIME_FORMAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 带异常处理的转换(推荐:避免程序崩溃)
|
||||
*/
|
||||
public static LocalDateTime strToLocalDateTimeSafe(String timeStr) {
|
||||
try {
|
||||
return strToLocalDateTime(timeStr);
|
||||
} catch (Exception e) {
|
||||
// 日志记录转换失败原因(企业级:必加)
|
||||
System.err.println("时间字符串转换失败,str=" + timeStr + ",错误:" + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
package com.agri.common.utils;
|
||||
|
||||
/**
|
||||
* @ClassName TimeRangeUtil
|
||||
* @Description TODO
|
||||
* @Author lld
|
||||
* @Date 2026/3/6 2:09
|
||||
* @Version 1.0
|
||||
*/
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
public class TimeRangeUtil {
|
||||
|
||||
/**
|
||||
* 判断dtu上报时间的时分秒是否在auto_term的时间区间内(支持跨天)
|
||||
*/
|
||||
public static boolean isTimeInRange(LocalDateTime dtuTime, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
if (dtuTime == null || startTime == null || endTime == null) {
|
||||
return false;
|
||||
}
|
||||
LocalTime currentTime = dtuTime.toLocalTime();
|
||||
LocalTime beforeTime = startTime.toLocalTime();
|
||||
LocalTime afterTime = endTime.toLocalTime();
|
||||
|
||||
if (startTime.isBefore(endTime)) {
|
||||
// 正常时段:08:00:00 - 18:00:00
|
||||
return !currentTime.isBefore(beforeTime) && !currentTime.isAfter(afterTime);
|
||||
} else {
|
||||
// 跨天时段:22:00:00 - 06:00:00
|
||||
return currentTime.isAfter(beforeTime) || currentTime.isBefore(afterTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ts(毫秒时间戳)转换并判断
|
||||
*/
|
||||
public static boolean isTsInRange(long ts, LocalDateTime startTime, LocalDateTime endTime) {
|
||||
LocalDateTime dtuTime = LocalDateTime.ofInstant(
|
||||
java.time.Instant.ofEpochMilli(ts),
|
||||
java.time.ZoneId.systemDefault()
|
||||
);
|
||||
return isTimeInRange(dtuTime, startTime, endTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,22 +1,5 @@
|
|||
package com.agri.common.utils.http;
|
||||
|
||||
import com.agri.common.constant.Constants;
|
||||
import com.agri.common.utils.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
|
@ -28,6 +11,17 @@ import java.net.URL;
|
|||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.agri.common.constant.Constants;
|
||||
import com.agri.common.utils.StringUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* 通用http发送方法
|
||||
|
|
@ -38,69 +32,6 @@ public class HttpUtils
|
|||
{
|
||||
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
|
||||
|
||||
// 静态RestTemplate(全局唯一,线程安全)
|
||||
private static final RestTemplate restTemplate;
|
||||
|
||||
// 静态代码块:初始化RestTemplate(项目启动时执行一次)
|
||||
static {
|
||||
// 配置超时时间,避免连接卡死
|
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
|
||||
factory.setConnectTimeout(5000); // 连接超时5秒
|
||||
factory.setReadTimeout(5000); // 读取超时5秒
|
||||
// 初始化静态RestTemplate
|
||||
restTemplate = new RestTemplate(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态通用POST请求(核心方法)
|
||||
* @param url 请求地址
|
||||
* @param requestBody 请求体(实体类/Map/JSON字符串)
|
||||
* @param contentType Content-Type(如application/json)
|
||||
* @param responseType 响应类型(String.class/自定义实体.class)
|
||||
* @return 响应结果
|
||||
*/
|
||||
public static <T, R> R post(String url, T requestBody, String contentType, Class<R> responseType) {
|
||||
// 前置校验:避免空指针
|
||||
if (url == null || url.isEmpty()) {
|
||||
throw new IllegalArgumentException("请求URL不能为空");
|
||||
}
|
||||
if (contentType == null || contentType.isEmpty()) {
|
||||
throw new IllegalArgumentException("Content-Type不能为空");
|
||||
}
|
||||
if (restTemplate == null) {
|
||||
throw new IllegalStateException("RestTemplate初始化失败,请检查配置");
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 构建请求头
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.parseMediaType(contentType));
|
||||
|
||||
// 2. 封装请求实体
|
||||
HttpEntity<T> requestEntity = new HttpEntity<>(requestBody, headers);
|
||||
|
||||
// 3. 发送POST请求
|
||||
return restTemplate.postForObject(url, requestEntity, responseType);
|
||||
} catch (RestClientException e) {
|
||||
// 详细异常信息,方便定位问题
|
||||
throw new RuntimeException(
|
||||
String.format("HTTP POST请求失败!url=%s, contentType=%s", url, contentType),
|
||||
e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态简化版POST请求(响应默认String)
|
||||
* @param url 请求地址
|
||||
* @param requestBody 请求体
|
||||
* @param contentType Content-Type
|
||||
* @return 字符串响应
|
||||
*/
|
||||
public static <T> String post(String url, T requestBody, String contentType) {
|
||||
return post(url, requestBody, contentType, String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向指定 URL 发送GET方法的请求
|
||||
*
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public class AddressUtils
|
|||
private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
|
||||
|
||||
// IP地址查询
|
||||
public static final String IP_URL = "https://whois.pconline.com.cn/ipJson.jsp";
|
||||
public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
|
||||
|
||||
// 未知地址
|
||||
public static final String UNKNOWN = "XX XX";
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
package com.agri.common.utils.wechat;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.agri.common.utils.http.HttpUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @Auther: jone
|
||||
* @Date: 2026/1/24 - 01 - 24 - 21:12
|
||||
* @Description: com.agri.common.utils.wechat
|
||||
* @version: 1.0
|
||||
*/
|
||||
public class WxUtil {
|
||||
|
||||
|
||||
private static final String WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=3cfeb466-76b9-4cf9-b03b-2324a2c3900f";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public static Map pushText(String param) {
|
||||
// 1. 构建请求参数
|
||||
Map<String, Object> requestBody = MapUtil.<String, Object>builder()
|
||||
.put("msgtype", "text")
|
||||
.put("text", MapUtil.<String, Object>builder()
|
||||
.put("content", param)
|
||||
.build())
|
||||
.build();
|
||||
return HttpUtils.post(WEBHOOK_URL,
|
||||
requestBody, MediaType.APPLICATION_JSON_VALUE, Map.class);
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ public class MybatisPlusHandler implements MetaObjectHandler {
|
|||
// 填充创建时间(字段名:createTime,值:当前时间)
|
||||
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
|
||||
// 示例:填充创建人(假设从上下文获取当前用户ID)
|
||||
this.strictInsertFill(metaObject, "createBy", String.class, getLoginUser()!=null?getLoginUser().getUsername():"");
|
||||
this.strictInsertFill(metaObject, "createBy", String.class, getLoginUser().getUsername());
|
||||
}
|
||||
|
||||
// 更新操作时自动填充
|
||||
|
|
@ -40,6 +40,6 @@ public class MybatisPlusHandler implements MetaObjectHandler {
|
|||
// 填充更新时间(字段名:updateTime,值:当前时间)
|
||||
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
|
||||
// 示例:填充更新人
|
||||
this.strictUpdateFill(metaObject, "updateBy", String.class, getLoginUser()!=null?getLoginUser().getUsername():"");
|
||||
this.strictUpdateFill(metaObject, "updateBy", String.class, getLoginUser().getUsername());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package com.agri.framework.config;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Configuration // 必须加
|
||||
public class RestTemplateConfig {
|
||||
@Bean // 必须加,声明RestTemplate为Spring Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ public class SecurityConfig
|
|||
.authorizeHttpRequests((requests) -> {
|
||||
permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
|
||||
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
|
||||
requests.antMatchers("/login", "/register", "/captchaImage","/api/mqtt/status","/test/user/getStatus").permitAll()
|
||||
requests.antMatchers("/login", "/register", "/captchaImage","/api/mqtt/status").permitAll()
|
||||
// 静态资源,可匿名访问
|
||||
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
|
||||
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
|
|
@ -62,17 +60,4 @@ public class ThreadPoolConfig
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean("mqttPushExecutor")
|
||||
public Executor mqttPushExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(10);
|
||||
executor.setMaxPoolSize(50);
|
||||
executor.setQueueCapacity(2000);
|
||||
executor.setThreadNamePrefix("mqtt-push-");
|
||||
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
executor.setAwaitTerminationSeconds(60);
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,148 +0,0 @@
|
|||
package com.agri.framework.interceptor;
|
||||
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.system.domain.SysAgriLimit;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
import com.agri.system.service.ISysAgriLimitService;
|
||||
import com.agri.system.service.ISysDevOperLogService;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Component
|
||||
public class DeviceAckHandler {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(DeviceAckHandler.class);
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* 自动关任务管理器,调度/取消自动关任务
|
||||
*/
|
||||
@Resource
|
||||
private MqttAutoOffManager mqttAutoOffManager;
|
||||
|
||||
/**
|
||||
* 农业限制服务,查询设备自动关延迟配置
|
||||
*/
|
||||
@Resource
|
||||
private ISysAgriLimitService agriLimitService;
|
||||
|
||||
@Autowired
|
||||
private ISysDevOperLogService sysDevOperLogService;
|
||||
|
||||
|
||||
// 初始化映射(建议放在类初始化块/构造方法中,只初始化一次)
|
||||
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
|
||||
private static final Set<String> VALID_FUNC_CODES = new HashSet<>();
|
||||
static {
|
||||
LIMIT_MAP.put("jm1g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1gLimit())));
|
||||
LIMIT_MAP.put("jm2g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2gLimit())));
|
||||
LIMIT_MAP.put("jbg1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbgLimit())));
|
||||
LIMIT_MAP.put("jm3g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3gLimit())));
|
||||
LIMIT_MAP.put("jm2k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2kLimit())));
|
||||
LIMIT_MAP.put("jm3k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3kLimit())));
|
||||
LIMIT_MAP.put("jbk1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbkLimit())));
|
||||
LIMIT_MAP.put("jm1k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1kLimit())));
|
||||
|
||||
VALID_FUNC_CODES.add("jm1g");
|
||||
VALID_FUNC_CODES.add("jm2g");
|
||||
VALID_FUNC_CODES.add("jbg");
|
||||
VALID_FUNC_CODES.add("jm3g");
|
||||
VALID_FUNC_CODES.add("jm2k");
|
||||
VALID_FUNC_CODES.add("jm3k");
|
||||
VALID_FUNC_CODES.add("jbk");
|
||||
VALID_FUNC_CODES.add("jm1k");
|
||||
}
|
||||
|
||||
public void isStartAutoOffTask(JSONObject payloadObj, String deviceId, String payload) {
|
||||
if (payloadObj.containsKey("suc") && payloadObj.containsKey("prop")) {
|
||||
JSONObject propObj = payloadObj.getJSONObject("prop");
|
||||
if (propObj != null && !propObj.isEmpty()) {
|
||||
boolean suc = payloadObj.getBooleanValue("suc");
|
||||
|
||||
for (Map.Entry<String, Object> propEntry : propObj.entrySet()) {
|
||||
String funcType = propEntry.getKey();
|
||||
Integer funcValue = parseFuncValue(propEntry.getValue());
|
||||
|
||||
processAck(deviceId, funcType, funcValue, suc);
|
||||
}
|
||||
|
||||
if (propObj.size() > 1) {
|
||||
log.info("【设备回执】设备{}的{}个功能已处理", deviceId, propObj.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processAck(String deviceId, String funcType, Integer funcValue, boolean suc) {
|
||||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
Boolean delete = stringRedisTemplate.delete(lockKey);
|
||||
log.info("【设备回执】设备{}的{}功能执行完成,已释放锁:{},{}", deviceId, funcType, lockKey, delete);
|
||||
|
||||
int runTime = 0;
|
||||
if (suc && StringUtils.hasText(funcType) && funcValue != null && funcValue == 1) {
|
||||
SysAgriLimit agriLimit = agriLimitService.lambdaQuery()
|
||||
.eq(SysAgriLimit::getImei, deviceId)
|
||||
.one();
|
||||
if (agriLimit != null) {
|
||||
int autoOffSeconds = LIMIT_MAP.getOrDefault(funcType, k -> 0).apply(agriLimit);
|
||||
runTime = autoOffSeconds;
|
||||
if (autoOffSeconds > 0) {
|
||||
mqttAutoOffManager.scheduleAutoOff(deviceId, funcType, autoOffSeconds);
|
||||
log.debug("【自动关任务】标记需要执行,deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (suc && StringUtils.hasText(funcType) && funcValue != null && funcValue == 0) {
|
||||
mqttAutoOffManager.cancelAutoOff(deviceId, funcType);
|
||||
}
|
||||
|
||||
boolean isTask = (Objects.equals(funcValue, 1)) && (runTime > 0);
|
||||
sysDevOperLogService.lambdaUpdate()
|
||||
.eq(SysDevOperLog::getImei, deviceId)
|
||||
.eq(SysDevOperLog::getFuncCode, funcType)
|
||||
.eq(SysDevOperLog::getOpType, funcValue)
|
||||
.eq(SysDevOperLog::getLockAcquired, 1)
|
||||
.orderByDesc(SysDevOperLog::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
.set(SysDevOperLog::getAckReceived, 1)
|
||||
.set(SysDevOperLog::getAckSuc, suc ? 1 : 0)
|
||||
.set(SysDevOperLog::getIsLockSuc, delete ? 1 : 0)
|
||||
.set(SysDevOperLog::getIsTask, isTask ? 1 : 0)
|
||||
.set(isTask, SysDevOperLog::getRunTime, runTime)
|
||||
.set(isTask, SysDevOperLog::getNoTaskReason, runTime > 0 ? null : "【自动关任务】标记不符合执行运行时间未配置,当前运行时间:【" + runTime + " s】")
|
||||
.set(SysDevOperLog::getUpdateBy, "设备回执")
|
||||
.set(SysDevOperLog::getAck, "{funcType:" + funcType + ", value:" + funcValue + "}")
|
||||
.update();
|
||||
}
|
||||
|
||||
private Integer parseFuncValue(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(String.valueOf(value));
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,323 +0,0 @@
|
|||
package com.agri.framework.interceptor;
|
||||
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.framework.manager.MqttSubscriptionManager;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
import com.agri.system.domain.SysUserAgri;
|
||||
import com.agri.system.service.AgriService;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.util.UrlEncodeUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 设备状态消息处理器
|
||||
* 核心功能:
|
||||
* 1. 处理设备状态上报、设备回执消息
|
||||
* 2. 触发自动关闭任务、取消自动关闭任务
|
||||
* 3. 转发设备状态到订阅的前端
|
||||
* 4. 维护设备最新状态缓存
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class DeviceStatusHandler {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(DeviceStatusHandler.class);
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* MQTT消息发送工具类(由MqttConfig配置类注入)
|
||||
*/
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
/**
|
||||
* MQTT订阅关系管理器,处理批量Redis操作
|
||||
*/
|
||||
@Resource
|
||||
private MqttSubscriptionManager mqttSubscriptionManager;
|
||||
|
||||
@Autowired
|
||||
private DeviceAckHandler deviceAckHandler;
|
||||
|
||||
@Autowired
|
||||
private ISysAgriInfoService agriInfoService;
|
||||
// 新增:最新状态缓存TTL(设备每10秒上报一次,缓存一小段时间即可)
|
||||
@Value("${spring.mqtt.latest-ttl-seconds:120}")
|
||||
private int latestTtlSeconds;
|
||||
|
||||
@Autowired
|
||||
private AgriService agriService;
|
||||
|
||||
private static final String AUTO_MODE = "auto_mode";
|
||||
private static final String AUTO_OFF = "autooff";
|
||||
|
||||
@Resource
|
||||
private FrontendControlHandler frontendControlHandler;
|
||||
/**
|
||||
* 自动关任务管理器,调度/取消自动关任务
|
||||
*/
|
||||
@Resource
|
||||
private MqttAutoOffManager mqttAutoOffManager;
|
||||
|
||||
private static final Set<String> VALID_FUNC_CODES = new HashSet<>();
|
||||
static {
|
||||
VALID_FUNC_CODES.add("jm1g");
|
||||
VALID_FUNC_CODES.add("jm2g");
|
||||
VALID_FUNC_CODES.add("jbg");
|
||||
VALID_FUNC_CODES.add("jm3g");
|
||||
VALID_FUNC_CODES.add("jm2k");
|
||||
VALID_FUNC_CODES.add("jm3k");
|
||||
VALID_FUNC_CODES.add("jbk");
|
||||
VALID_FUNC_CODES.add("jm1k");
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设备状态:转发给订阅的前端、处理回执、触发自动关
|
||||
*/
|
||||
public void handle(String topic, String payload) {
|
||||
|
||||
// log.info("【设备处理】JSON解析:{}",payloadObj);
|
||||
// 解析设备ID:主题格式为dtu/{deviceId}/up,分割后第2个元素是设备ID
|
||||
String deviceId = extractDeviceId(topic);
|
||||
if (deviceId == null) return;
|
||||
String[] segments = topic.split("/");
|
||||
String action = segments[2];
|
||||
if ("down".equals(action) || !isJsonObjectLike(payload)) return;
|
||||
|
||||
// 第一步:解析JSON,非有效JSON直接return
|
||||
JSONObject payloadObj;
|
||||
try {
|
||||
payloadObj = JSON.parseObject(payload);
|
||||
} catch (Exception e) {
|
||||
log.error("【设备处理】JSON解析失败,payload={}", payload, e);
|
||||
return;
|
||||
}
|
||||
if (payloadObj == null || payloadObj.isEmpty()) {
|
||||
log.warn("【设备处理】JSON解析后为空,payload={}", payload);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isAck = payloadObj.containsKey("suc") && payloadObj.containsKey("prop");
|
||||
JSONObject sendObj = payloadObj; // 默认直接用原对象
|
||||
// 如果是回执,先拿 funcType
|
||||
|
||||
if (isAck) {
|
||||
JSONObject propObj = payloadObj.getJSONObject("prop");
|
||||
if (propObj != null && !propObj.isEmpty()) {
|
||||
String funcType = propObj.entrySet().iterator().next().getKey();
|
||||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
|
||||
// 读取锁的 value(比如 autooff / user:1001)
|
||||
String lockHolder = stringRedisTemplate.opsForValue().get(lockKey);
|
||||
if (lockHolder != null) {
|
||||
sendObj = new JSONObject(payloadObj); // 只在需要时复制
|
||||
sendObj.put("clientId", lockHolder);
|
||||
// 如果相等则为自动模式直接退出方法 不转发ack消息 自动关也不应该转发
|
||||
if (AUTO_MODE.equals(lockHolder) || AUTO_OFF.equals(lockHolder)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 转发消息
|
||||
forwardPayload(deviceId, payload,payloadObj,action, sendObj, isAck);
|
||||
// 获取第二个动态段,如"up"或"ack"
|
||||
if ("ack".equals(action)) {
|
||||
deviceAckHandler.isStartAutoOffTask(payloadObj,deviceId,payload);
|
||||
return;
|
||||
}
|
||||
// payload全部为数字
|
||||
if ("up".equals(action) && isAllKeysDigit(payloadObj)) {
|
||||
SysAgriInfo agriInfo = agriInfoService.lambdaQuery()
|
||||
.eq(SysAgriInfo::getImei, deviceId)
|
||||
.one();
|
||||
if (agriInfo == null) {
|
||||
return;
|
||||
}
|
||||
// 温度上下限
|
||||
BigDecimal tempUp = agriInfo.getTempUp();
|
||||
BigDecimal tempLow = agriInfo.getTempLow();
|
||||
// 湿度上下限
|
||||
BigDecimal humiUp = agriInfo.getHumiUp();
|
||||
BigDecimal humiLow = agriInfo.getHumiLow();
|
||||
if (BigDecimal.ZERO.compareTo(tempUp) == 0
|
||||
&& BigDecimal.ZERO.compareTo(tempLow) == 0
|
||||
&& BigDecimal.ZERO.compareTo(humiUp) == 0
|
||||
&& BigDecimal.ZERO.compareTo(humiLow) == 0) return;
|
||||
List<SysAgriInfo> msgList = new ArrayList<>();
|
||||
// 仅当up且所有key为数字时,才更新最新状态缓存
|
||||
for (String key : payloadObj.keySet()) {
|
||||
BigDecimal value = payloadObj.getBigDecimal(key)
|
||||
.divide(new BigDecimal(10),1, RoundingMode.HALF_UP);
|
||||
String valueIndex = key.substring(2);
|
||||
SysAgriInfo sysAgriInfo = new SysAgriInfo();
|
||||
BeanUtils.copyProperties(agriInfo, sysAgriInfo);
|
||||
// 温度
|
||||
if (key.startsWith("20")) {
|
||||
// 温度大于温度上限
|
||||
if (value.compareTo(tempUp) > 0 ) {
|
||||
agriInfo.setTitle("温度异常");
|
||||
agriInfo.setMsg("温度"+valueIndex+ "异常!高于上限"+tempUp+"℃!");
|
||||
msgList.add(agriInfo);
|
||||
} else if (value.compareTo(tempLow) < 0) {
|
||||
agriInfo.setTitle("温度异常");
|
||||
agriInfo.setMsg("温度"+valueIndex+ "异常!低于下限"+tempLow+"℃!");
|
||||
msgList.add(agriInfo);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 湿度
|
||||
if (key.startsWith("10")) {
|
||||
// 湿度大于湿度上限
|
||||
if (value.compareTo(humiUp) > 0 ) {
|
||||
agriInfo.setTitle("湿度异常");
|
||||
agriInfo.setMsg("湿度"+valueIndex+ "异常!高于上限"+humiUp+"RH%!");
|
||||
msgList.add(agriInfo);
|
||||
} else if (value.compareTo(humiLow) < 0) {
|
||||
agriInfo.setTitle("湿度异常");
|
||||
agriInfo.setMsg("湿度"+valueIndex+ "异常!低于下限"+humiLow+"RH%!");
|
||||
msgList.add(agriInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!msgList.isEmpty()) {
|
||||
List<SysMessage> messages = agriService.saveMessage(msgList);
|
||||
try {
|
||||
frontendControlHandler.sendAlarmMessage(messages);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void forwardPayload(String deviceId,String payload,
|
||||
JSONObject payloadObj,String action, JSONObject sendObj, boolean isAck) {
|
||||
try {
|
||||
|
||||
// 非回执消息:正常转发给订阅前端
|
||||
// 查询Redis中订阅该设备的前端列表:sub:{deviceId}
|
||||
Set<String> subscribedClients = stringRedisTemplate.opsForSet().members("sub:" + deviceId);
|
||||
|
||||
if (subscribedClients != null && !subscribedClients.isEmpty()) {
|
||||
// 推送给每个订阅的前端
|
||||
// 方案B:不再依赖online:;改为校验subc:{clientId}是否仍包含deviceId(取消订阅失败/异常退出兜底)
|
||||
List<String> clients = new ArrayList<>(subscribedClients);
|
||||
// 判断subc是否还存在 一次性查全部 获取失效的clientId
|
||||
List<Boolean> stillSubs = mqttSubscriptionManager.pipeIsMemberSubc(clients, deviceId);
|
||||
|
||||
// 关系不存在:清理sub:{deviceId}残留,避免一直给前端发
|
||||
List<String> stale = null;
|
||||
|
||||
for (int i = 0; i < clients.size(); i++) {
|
||||
String clientId = clients.get(i);
|
||||
boolean stillSub = i < stillSubs.size() && Boolean.TRUE.equals(stillSubs.get(i));
|
||||
if (!stillSub) {
|
||||
if (stale == null) {
|
||||
stale = new ArrayList<>();
|
||||
}
|
||||
// false不存在添加队列
|
||||
stale.add(clientId);
|
||||
continue;
|
||||
}
|
||||
// 前端专属主题:frontend/{clientId}/dtu/{deviceId}/listener
|
||||
String frontendTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
|
||||
if ("ack".equals(action)) {
|
||||
frontendTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/ack";
|
||||
}
|
||||
// 发布消息
|
||||
mqttMessageSender.publish(frontendTopic, sendObj.toJSONString());
|
||||
// log.info("【设备状态转发】设备{} → 前端{},主题:{}", deviceId, clientId, frontendTopic);
|
||||
}
|
||||
// 删掉设备对应的客户端
|
||||
if (stale != null && !stale.isEmpty()) {
|
||||
mqttSubscriptionManager.pipeSRemSub(deviceId, stale);
|
||||
}
|
||||
} else {
|
||||
// 优化:替换System.out为log.info
|
||||
// log.info("【设备状态转发】设备{}无订阅前端,跳过转发", deviceId);
|
||||
}
|
||||
|
||||
// 第三步:仅处理非回执的设备状态包,且仅当是8个功能码结构就写入Redis
|
||||
// 有没有人订阅都得写,只要发送设备开的指令成功了就得写
|
||||
if (!isAck) {
|
||||
// 1) 先校验状态包是否包含8个固定功能码(核心:只有这种结构才写入)
|
||||
boolean isValidStatus = true;
|
||||
for (String validCode : VALID_FUNC_CODES) {
|
||||
if (!payloadObj.containsKey(validCode)) {
|
||||
isValidStatus = false;
|
||||
// log.debug("【设备状态包】结构不合法(非8个功能码),跳过Redis写入,deviceId={};payload={}", deviceId, payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mqttAutoOffManager.hasAutoOffTask(deviceId) && isValidStatus) {
|
||||
// ✅ 8个功能码状态包:无条件写device:latest:{deviceId},避免自动关读不到最新状态
|
||||
stringRedisTemplate.opsForValue().set(
|
||||
"device:latest:" + deviceId,
|
||||
payload, // 完整的8功能码JSON
|
||||
latestTtlSeconds,
|
||||
TimeUnit.SECONDS
|
||||
);
|
||||
// log.debug("【设备状态包】写入Redis成功,deviceId={}", deviceId);
|
||||
}
|
||||
}
|
||||
} catch (MqttException e) {
|
||||
WxUtil.pushText(
|
||||
"【消息转发失败】\n deviceId: "+deviceId+"\n payload: "+payload+"\n cause: "+e);
|
||||
log.error("【消息转发失败】deviceId={}, msg={}", deviceId, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String extractDeviceId(String topic) {
|
||||
int first = topic.indexOf('/');
|
||||
if (first < 0) return null;
|
||||
int second = topic.indexOf('/', first + 1);
|
||||
if (second < 0) return null;
|
||||
return topic.substring(first + 1, second);
|
||||
}
|
||||
|
||||
private boolean isJsonObjectLike(String s) {
|
||||
if (s == null) return false;
|
||||
int n = s.length();
|
||||
for (int i = 0; i < n; i++) {
|
||||
char c = s.charAt(i);
|
||||
if (!Character.isWhitespace(c)) return c == '{';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isAllKeysDigit(JSONObject obj) {
|
||||
return obj != null && !obj.isEmpty()
|
||||
&& obj.keySet().stream().allMatch(k -> k.matches("\\d+"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
package com.agri.framework.interceptor;
|
||||
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.system.domain.SysRollerAir;
|
||||
import com.agri.system.service.*;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
public class FrontendConfigHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FrontendConfigHandler.class);
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
@Autowired
|
||||
private ISysRollerAirService sysRollerAirService;
|
||||
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
||||
private int dtuCtlLockTTL;
|
||||
|
||||
@Value("${agri.per-lap.len}")
|
||||
private BigDecimal perLapLen;
|
||||
|
||||
@Value("${agri.per-lap.sec}")
|
||||
private BigDecimal perLapSec;
|
||||
/**
|
||||
* 处理前端控制指令:权限校验+分布式锁+转发给设备
|
||||
*/
|
||||
public void handle(String topic, String payload) throws MqttException {
|
||||
// 解析前端clientId、设备ID
|
||||
String[] parts = topic.split("/");
|
||||
String clientId = parts[1];
|
||||
String deviceId = parts[2];
|
||||
|
||||
// 新增:入参非空校验(JDK 8兼容)
|
||||
if (!StringUtils.hasText(clientId) || !StringUtils.hasText(deviceId)) {
|
||||
log.error("【指令处理】clientId或deviceId为空,topic={}", topic);
|
||||
return;
|
||||
}
|
||||
// 解析功能码({"功能码":状态码}格式)
|
||||
Map<String, Integer> funcCodeMap = null;
|
||||
try {
|
||||
funcCodeMap = JSON.parseObject(payload, new TypeReference<Map<String, Integer>>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("【指令处理】功能码解析失败,payload={}", payload, e);
|
||||
return;
|
||||
}
|
||||
if (funcCodeMap == null || funcCodeMap.isEmpty()) {
|
||||
log.warn("【指令处理】前端{}操作设备{}失败:功能码为空", clientId, deviceId);
|
||||
return;
|
||||
}
|
||||
// 提取第一个功能码作为锁标识
|
||||
String funcType = funcCodeMap.keySet().iterator().next();
|
||||
|
||||
// 2. 分布式锁:设备ID+功能类型(避免同设备同功能并发控制)
|
||||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
|
||||
lockKey, clientId, dtuCtlLockTTL, TimeUnit.SECONDS // 延长至15秒,适配设备回执场景
|
||||
);
|
||||
if (lockSuccess == null || !lockSuccess) {
|
||||
String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
|
||||
mqttMessageSender.publish(errorTopic, "{\"msg\":\"设备" + funcType + "功能忙,请稍后重试\",\"clientId\":\""+clientId+"\"}");
|
||||
log.warn("【分布式锁】前端{}操作设备{}的{}功能失败;可能其他用户正在操作此功能", clientId, deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 转发前端指令
|
||||
String deviceTopic = "dtu/" + deviceId + "/down";
|
||||
mqttMessageSender.publish(deviceTopic, payload);
|
||||
LocalDateTime currentTime = LocalDateTime.now();
|
||||
// 3. 记录日志
|
||||
log.info("【指令处理】前端{}于{}控制设备{}的{}功能,指令:{}",
|
||||
clientId, currentTime, deviceId, funcType, payload);
|
||||
|
||||
String funcName = funcType.substring(0, funcType.length() - 1);
|
||||
Integer funcCode = funcCodeMap.get(funcType);
|
||||
|
||||
// 当卷膜 开 暂停,才执行的逻辑
|
||||
if (funcCode == 0 && funcType.contains("k")) {
|
||||
SysRollerAir sysRollerAir = sysRollerAirService.lambdaQuery()
|
||||
.eq(SysRollerAir::getImei, deviceId)
|
||||
.eq(SysRollerAir::getRoller, funcName)
|
||||
.eq(SysRollerAir::getOpType, 1)
|
||||
.orderByDesc(SysRollerAir::getId)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
BigDecimal ventTotalLen = BigDecimal.ZERO;
|
||||
if (ObjectUtils.isNotEmpty(sysRollerAir)
|
||||
&& sysRollerAir.getOpTime().isBefore(currentTime)) {
|
||||
|
||||
long time = Math.abs(Duration.between(currentTime, sysRollerAir.getOpTime()).getSeconds());
|
||||
BigDecimal ventTotalTime = BigDecimal.valueOf(time);
|
||||
|
||||
// 除以一圈的时间乘以一圈的长度
|
||||
ventTotalLen = ventTotalTime.divide(perLapSec, 2, RoundingMode.HALF_UP)
|
||||
.multiply(perLapLen).setScale(2, RoundingMode.HALF_UP);
|
||||
log.info("【自动化参数】卷膜校准时间:{}; 一圈秒数:{}; 一圈长度: {}", ventTotalTime,perLapSec,perLapLen);
|
||||
}
|
||||
String config = "{\"ventTotalLen\": " + ventTotalLen +",\"clientId\":\""+clientId+"\"}";
|
||||
// 查数据库、最后一条卷膜开暂停。计算时间发送自动关时间
|
||||
mqttMessageSender.publish("frontend/"+clientId+"/dtu/"+deviceId+"/config", config);
|
||||
}
|
||||
// 插入记录
|
||||
SysRollerAir rollerAir = new SysRollerAir();
|
||||
rollerAir.setImei(deviceId);
|
||||
rollerAir.setRoller(funcName);
|
||||
rollerAir.setOpType(funcCode);
|
||||
rollerAir.setPayload(payload);
|
||||
rollerAir.setClientid(clientId);
|
||||
rollerAir.setOpTime(currentTime);
|
||||
sysRollerAirService.save(rollerAir);
|
||||
log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType);
|
||||
} finally {
|
||||
stringRedisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,277 +0,0 @@
|
|||
package com.agri.framework.interceptor;
|
||||
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysAgriLimit;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
import com.agri.system.mapper.SysUserMapper;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.service.ISysAgriLimitService;
|
||||
import com.agri.system.service.ISysDevOperLogService;
|
||||
import com.agri.system.service.ISysUserService;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 前端控制指令处理器
|
||||
* 核心功能:
|
||||
* 1. 解析前端控制指令,校验入参合法性
|
||||
* 2. 前端操作设备权限校验
|
||||
* 3. 分布式锁控制,避免同设备同功能并发指令
|
||||
* 4. 转发前端指令到设备端
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class FrontendControlHandler {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(FrontendControlHandler.class);
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* MQTT消息发送工具类(由MqttConfig配置类注入)
|
||||
*/
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
@Resource
|
||||
private MqttAutoOffManager mqttAutoOffManager;
|
||||
|
||||
@Autowired
|
||||
private ISysAgriLimitService agriLimitService;
|
||||
|
||||
@Autowired
|
||||
private ISysAgriInfoService sysAgriInfoService;
|
||||
@Autowired
|
||||
private ISysDevOperLogService sysDevOperLogService;
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Autowired
|
||||
private ISysUserService sysUserService;
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
||||
private int dtuCtlLockTTL;
|
||||
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
|
||||
static {
|
||||
LIMIT_MAP.put("jm1g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1gLimit())));
|
||||
LIMIT_MAP.put("jm2g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2gLimit())));
|
||||
LIMIT_MAP.put("jbg1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbgLimit())));
|
||||
LIMIT_MAP.put("jm3g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3gLimit())));
|
||||
LIMIT_MAP.put("jm2k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2kLimit())));
|
||||
LIMIT_MAP.put("jm3k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3kLimit())));
|
||||
LIMIT_MAP.put("jbk1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbkLimit())));
|
||||
LIMIT_MAP.put("jm1k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1kLimit())));
|
||||
}
|
||||
/**
|
||||
* 处理前端控制指令:权限校验+分布式锁+转发给设备
|
||||
*/
|
||||
public void handle(String topic, String payload) throws MqttException {
|
||||
// 解析前端clientId、设备ID
|
||||
String[] parts = topic.split("/");
|
||||
String clientId = parts[1];
|
||||
String deviceId = parts[3];
|
||||
|
||||
// 新增:入参非空校验(JDK 8兼容)
|
||||
if (!StringUtils.hasText(clientId) || !StringUtils.hasText(deviceId)) {
|
||||
log.error("【指令处理】clientId或deviceId为空,topic={}", topic);
|
||||
return;
|
||||
}
|
||||
// 1. 权限校验(示例:admin开头有全权限)
|
||||
if (!checkPermission(clientId, deviceId)) {
|
||||
String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
|
||||
mqttMessageSender.publish(errorTopic, "{\"msg\":\"无设备操作权限\"}");
|
||||
log.warn("【权限校验】前端{}操作设备{}失败", clientId, deviceId);
|
||||
return;
|
||||
}
|
||||
// 4. 转发指令到设备
|
||||
String deviceTopic = "dtu/" + deviceId + "/down";
|
||||
JSONObject payloadObj;
|
||||
try {
|
||||
payloadObj = JSON.parseObject(payload);
|
||||
} catch (Exception e) {
|
||||
log.error("【设备处理】JSON解析失败,payload={}", payload, e);
|
||||
return;
|
||||
}
|
||||
if (payloadObj.containsKey("read")) {
|
||||
mqttMessageSender.publish(deviceTopic, payload);
|
||||
log.info("【主动读取】设备{}主动读取,payload={}",deviceId, payload);
|
||||
return;
|
||||
}
|
||||
// 解析功能码({"功能码":状态码}格式)
|
||||
Map<String, Integer> funcCodeMap = null;
|
||||
try {
|
||||
funcCodeMap = JSON.parseObject(payload, new TypeReference<Map<String, Integer>>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("【指令处理】功能码解析失败,payload={}", payload, e);
|
||||
String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
|
||||
mqttMessageSender.publish(errorTopic, "{\"msg\":\"指令格式错误\"}");
|
||||
return;
|
||||
}
|
||||
if (funcCodeMap == null || funcCodeMap.isEmpty()) {
|
||||
String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
|
||||
mqttMessageSender.publish(errorTopic, "{\"msg\":\"功能码不能为空\"}");
|
||||
log.warn("【指令处理】前端{}操作设备{}失败:功能码为空", clientId, deviceId);
|
||||
return;
|
||||
}
|
||||
// 提取第一个功能码作为锁标识
|
||||
String funcType = funcCodeMap.keySet().iterator().next();
|
||||
|
||||
// 2. 分布式锁:设备ID+功能类型(避免同设备同功能并发控制)
|
||||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
|
||||
lockKey, clientId, dtuCtlLockTTL, TimeUnit.SECONDS // 延长至15秒,适配设备回执场景
|
||||
);
|
||||
if (lockSuccess == null || !lockSuccess) {
|
||||
String errorTopic = "frontend/" + clientId + "/dtu/" + deviceId + "/listener";
|
||||
mqttMessageSender.publish(errorTopic, "{\"msg\":\"设备" + funcType + "功能忙,请稍后重试\",\"clientId\":\""+clientId+"\"}");
|
||||
log.warn("【分布式锁】前端{}操作设备{}的{}功能失败;可能其他用户正在操作此功能", clientId, deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 3. 记录日志
|
||||
log.info("【指令处理】前端{}于{}控制设备{}的{}功能,指令:{}",
|
||||
clientId, LocalDateTime.now(), deviceId, funcType, payload);
|
||||
SysUser sysUser = sysUserService.lambdaQuery()
|
||||
.eq(SysUser::getClientId, clientId)
|
||||
.one();
|
||||
String operator = "手动控制";
|
||||
if (sysUser!=null) {
|
||||
operator = sysUser.getUserName();
|
||||
}
|
||||
SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery()
|
||||
.eq(SysAgriInfo::getImei, deviceId)
|
||||
.one();
|
||||
String agriName = (agriInfo!=null && ObjectUtils.isNotEmpty(agriInfo.getAgriName()))?agriInfo.getAgriName():null;
|
||||
SysDevOperLog logDto = new SysDevOperLog();
|
||||
logDto.setAgriName(agriName);
|
||||
logDto.setImei(deviceId);
|
||||
logDto.setFuncCode(funcType);
|
||||
logDto.setOpType(funcCodeMap.get(funcType));
|
||||
logDto.setOpSource(1);
|
||||
logDto.setPayload(payload);
|
||||
logDto.setLockAcquired(1);
|
||||
logDto.setLockHolder(clientId);
|
||||
logDto.setCreateBy(operator);
|
||||
sysDevOperLogService.save(logDto);
|
||||
//todo
|
||||
mqttMessageSender.publish(deviceTopic, payload);
|
||||
// if (save) {
|
||||
// testAutoOffTask(deviceId,funcCodeMap);
|
||||
// }
|
||||
log.info("【指令转发】前端{} → 设备{}的{}功能", clientId, deviceId, funcType);
|
||||
} finally {
|
||||
stringRedisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
public void testAutoOffTask(String deviceId, Map<String,Integer> funcCodeMap) throws MqttException {
|
||||
|
||||
String funcType = funcCodeMap.keySet().iterator().next();
|
||||
Integer funcValue = funcCodeMap.get(funcType);
|
||||
// 释放对应功能的分布式锁
|
||||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
Boolean delete = stringRedisTemplate.delete(lockKey);
|
||||
if (delete) {
|
||||
log.info("【设备控制锁删除成功!】");
|
||||
}
|
||||
|
||||
// 回执成功且值=1时启动自动关闭任务(保留原有逻辑)
|
||||
if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 1) {
|
||||
SysAgriLimit agriLimit = agriLimitService.lambdaQuery()
|
||||
.eq(SysAgriLimit::getImei, deviceId)
|
||||
.one();
|
||||
int autoOffSeconds = 0;
|
||||
if (agriLimit != null) {
|
||||
autoOffSeconds = LIMIT_MAP.getOrDefault(funcType, k -> 0).apply(agriLimit);
|
||||
}
|
||||
// 新增:判断是否真的需要执行自动关任务(延迟秒数>0才是有效任务)
|
||||
if (autoOffSeconds > 0) {
|
||||
mqttAutoOffManager.scheduleAutoOff(deviceId, funcType, autoOffSeconds);
|
||||
log.debug("【自动关任务】标记需要执行,deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);
|
||||
|
||||
} else {
|
||||
log.debug("【自动关任务】标记不符合执行运行时间未配置,deviceId={}, funcType={}, delay={}s", deviceId, funcType, autoOffSeconds);
|
||||
}
|
||||
|
||||
sysDevOperLogService.lambdaUpdate()
|
||||
.eq(SysDevOperLog::getImei, deviceId)
|
||||
.eq(SysDevOperLog::getFuncCode, funcType)
|
||||
.eq(SysDevOperLog::getOpType, funcValue)
|
||||
.eq(SysDevOperLog::getLockAcquired,1)
|
||||
.orderByDesc(SysDevOperLog::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
.set(SysDevOperLog::getAckReceived,1)
|
||||
.set(SysDevOperLog::getIsLockSuc,1)
|
||||
.set(SysDevOperLog::getAckSuc, 1)
|
||||
.set(SysDevOperLog::getIsTask, 1)
|
||||
.set(autoOffSeconds <= 0, SysDevOperLog::getNoTaskReason,"当前运行时间:【"+autoOffSeconds+"】")
|
||||
.set(SysDevOperLog::getUpdateBy, "测试")
|
||||
.set(SysDevOperLog::getExecResult, 1)
|
||||
.update();
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(funcType) && funcValue != null && funcValue == 0) {
|
||||
mqttAutoOffManager.cancelAutoOff(deviceId, funcType);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 权限校验逻辑(示例)
|
||||
* 可根据业务需求扩展:
|
||||
* 1. 管理员前端(clientId以admin_开头)拥有所有权限
|
||||
* 2. 普通前端仅能操作Redis中绑定的设备(user_device:{clientId} → deviceId集合)
|
||||
*
|
||||
* @param clientId 前端唯一标识
|
||||
* @param deviceId 设备ID
|
||||
* @return true=有权限,false=无权限
|
||||
*/
|
||||
private boolean checkPermission(String clientId, String deviceId) {
|
||||
// 管理员权限:clientId以admin_开头
|
||||
// 普通用户权限:校验Redis中是否绑定该设备
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
public void sendAlarmMessage(List<SysMessage> messages) throws Exception {
|
||||
if (CollectionUtils.isEmpty(messages)) {
|
||||
return;
|
||||
}
|
||||
for (SysMessage message : messages) {
|
||||
Map<String, Object> alarmMsg = new HashMap<>();
|
||||
alarmMsg.put("msgType", message);
|
||||
String alarmMessage = objectMapper.writeValueAsString(alarmMsg);
|
||||
mqttMessageSender.publish("device/" + message.getImei() + "/alarm", alarmMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package com.agri.framework.interceptor;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 前端在线心跳处理器
|
||||
* 核心功能:
|
||||
* 1. 处理前端在线心跳消息
|
||||
* 2. 续期前端订阅关系TTL,兜底异常退出场景
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class FrontendOnlineHandler {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(FrontendOnlineHandler.class);
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
// 新增:前端订阅关系TTL(兜底“取消订阅失败/异常退出”)——只维护subc:{clientId}的TTL
|
||||
@Value("${spring.mqtt.subc-ttl-seconds:3600}")
|
||||
private int subcTtlSeconds;
|
||||
|
||||
/**
|
||||
* 新增:处理前端在线心跳:写入Redis在线标记(带TTL)
|
||||
* 主题格式:frontend/{clientId}/online
|
||||
*/
|
||||
public void handle(String topic, String payload) {
|
||||
try {
|
||||
String[] parts = topic.split("/");
|
||||
if (parts.length < 3) {
|
||||
return;
|
||||
}
|
||||
String clientId = parts[1];
|
||||
if (!StringUtils.hasText(clientId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 续期subc:{clientId}
|
||||
stringRedisTemplate.expire("subc:" + clientId, subcTtlSeconds, TimeUnit.SECONDS);
|
||||
|
||||
// todo 生产环境不建议打印每次心跳
|
||||
// log.debug("【在线心跳】clientId={} 续期subcTTL={}s payload={}", clientId, subcTtlSeconds, payload);
|
||||
} catch (Exception e) {
|
||||
log.warn("【在线心跳】处理失败 topic={} msg={}", topic, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,145 +0,0 @@
|
|||
package com.agri.framework.manager;
|
||||
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.framework.interceptor.FrontendControlHandler;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.service.AgriService;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class AgriStatusManager {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AgriStatusManager.class);
|
||||
|
||||
// Redis 前缀常量
|
||||
private static final String SUB_KEY_PREFIX = "sub:";
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
|
||||
// JSON序列化工具(单例)
|
||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||
|
||||
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Resource
|
||||
private FrontendControlHandler frontendControlHandler;
|
||||
@Autowired
|
||||
private AgriService agriService;
|
||||
|
||||
// ========== 批量查在线状态(Pipeline 优化版,JDK 8 适配) ==========
|
||||
// 在线离线的都得推
|
||||
public Map<String, Map<String, Boolean>> batchCheckDeviceOnline(List<String> imeiList) {
|
||||
Map<String, Map<String, Boolean>> result = new HashMap<>();
|
||||
if (imeiList.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// JDK 8 显式声明 RedisCallback,避免 Lambda 泛型问题
|
||||
List<Object> results = stringRedisTemplate.executePipelined(
|
||||
new RedisCallback<Object>() {
|
||||
@Override
|
||||
public Object doInRedis(RedisConnection connection) {
|
||||
StringRedisSerializer serializer = new StringRedisSerializer();
|
||||
for (String imei : imeiList) {
|
||||
byte[] onlineKeyBytes = serializer.serialize(SUB_KEY_PREFIX + imei);
|
||||
connection.exists(onlineKeyBytes); // 批量执行 exists
|
||||
connection.exists(serializer.serialize(imei));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
new StringRedisSerializer()
|
||||
);
|
||||
|
||||
// 解析结果:每两个结果对应一个IMEI(subExist + imeiOnline)
|
||||
for (int i = 0; i < imeiList.size(); i++) {
|
||||
String imei = imeiList.get(i);
|
||||
// 初始化默认状态:不存在+离线
|
||||
boolean subExist = false;
|
||||
boolean imeiOnline = false;
|
||||
|
||||
// 越界判断:避免IndexOutOfBoundsException
|
||||
int subIndex = i * 2;
|
||||
int imeiIndex = i * 2 + 1;
|
||||
if (subIndex < results.size()) {
|
||||
Object subResult = results.get(subIndex);
|
||||
subExist = parseExistsResult(subResult);
|
||||
}
|
||||
if (imeiIndex < results.size()) {
|
||||
Object imeiResult = results.get(imeiIndex);
|
||||
imeiOnline = parseExistsResult(imeiResult);
|
||||
}
|
||||
result.put(imei, ImmutableMap.of("subExist", subExist, "imeiOnline", imeiOnline));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
private boolean parseExistsResult(Object result) {
|
||||
if (result instanceof Long) {
|
||||
return ((Long) result) == 1;
|
||||
} else if (result instanceof Boolean) {
|
||||
return (Boolean) result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// ========== 核心方法3:异步批量推送在线状态到 MQTT(线程池隔离) ==========
|
||||
@Async("mqttPushExecutor")
|
||||
public void asyncBatchPushMqtt(Map<String, Map<String, Boolean>> statusMap) {
|
||||
if (statusMap.isEmpty()) {
|
||||
log.info("不存在任何imei");
|
||||
return;
|
||||
}
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
String dateNow = LocalDateTime.now().format(DATE_TIME_FORMATTER);
|
||||
// 在线状态
|
||||
for (Map.Entry<String, Map<String, Boolean>> map : statusMap.entrySet()) {
|
||||
String imei = map.getKey();
|
||||
try {
|
||||
// 按你的需求,直接推送到 frontend/{imei}/online 主题
|
||||
Map<String, Boolean> imeiMap = map.getValue();
|
||||
|
||||
// 设备在线的 && 推送首页状态 离线在线都推
|
||||
if (imeiMap.get("subExist")) {
|
||||
// 构造首页消息(用ObjectMapper序列化,避免手动拼接JSON)
|
||||
Map<String, Object> onlineMsg = new HashMap<>();
|
||||
onlineMsg.put("online", imeiMap.get("imeiOnline") ? "在线" : "离线");
|
||||
onlineMsg.put("time", dateNow); // 毫秒时间戳
|
||||
onlineMsg.put("imei", imei);
|
||||
String onlineMessage = objectMapper.writeValueAsString(onlineMsg);
|
||||
mqttMessageSender.publish("device/" + imei + "/status", onlineMessage);
|
||||
}
|
||||
successCount++;
|
||||
} catch (Exception e) {
|
||||
failCount++;
|
||||
log.error("向设备 {} 推送在线状态失败", imei, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.info("批量在线状态推送完成:成功={},失败={}", successCount, failCount);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,407 +0,0 @@
|
|||
package com.agri.framework.manager;
|
||||
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.service.ISysDevOperLogService;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 设备自动关任务管理器
|
||||
* 核心功能:
|
||||
* 1. 初始化/优雅关闭自动关任务线程池
|
||||
* 2. 调度/取消设备功能自动关闭任务
|
||||
* 3. 执行自动关任务,校验设备最新状态
|
||||
* 4. 维护设备未完成自动关任务计数
|
||||
* 改造点:自动关闭任务改为多线程并行执行
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class MqttAutoOffManager {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(MqttAutoOffManager.class);
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
/**
|
||||
* MQTT消息发送工具类(由MqttConfig配置类注入)
|
||||
*/
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
// 改造:将单线程池改为固定线程池,支持多任务并行执行
|
||||
// 替代原有的 Executors.newSingleThreadScheduledExecutor()
|
||||
private ScheduledExecutorService autoOffExecutor;
|
||||
|
||||
// 新增:同设备同功能只保留最后一次自动关任务
|
||||
private final ConcurrentHashMap<String, ScheduledFuture<?>> autoOffFutureMap = new ConcurrentHashMap<>();
|
||||
|
||||
// 新增:按设备维度统计“未完成的自动关任务”数量,hasAutoOffTask从扫描O(N)降为O(1)
|
||||
private final ConcurrentHashMap<String, Integer> autoOffDeviceCnt = new ConcurrentHashMap<>();
|
||||
|
||||
// 新增:自动关闭任务线程池核心线程数(可配置)
|
||||
@Value("${spring.mqtt.auto-off-thread-pool-size:5}")
|
||||
private int autoOffThreadPoolSize;
|
||||
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
||||
private int dtuCtlLockTTL;
|
||||
|
||||
@Autowired
|
||||
private ISysAgriInfoService sysAgriInfoService;
|
||||
@Autowired
|
||||
private ISysDevOperLogService sysDevOperLogService;
|
||||
|
||||
|
||||
/**
|
||||
* 初始化自动关任务线程池
|
||||
* @param corePoolSize 核心线程数
|
||||
*/
|
||||
public void initExecutor(int corePoolSize) {
|
||||
// 初始化多线程池(固定线程数)
|
||||
autoOffExecutor = new ScheduledThreadPoolExecutor(
|
||||
autoOffThreadPoolSize, // 核心线程数
|
||||
r -> {
|
||||
Thread thread = new Thread(r);
|
||||
thread.setName("auto-off-task-" + thread.getId());
|
||||
thread.setDaemon(true); // 设置为守护线程,不阻塞JVM退出
|
||||
return thread;
|
||||
},
|
||||
new ThreadPoolExecutor.CallerRunsPolicy() // 队列压力或关闭时兜底不丢任务
|
||||
);
|
||||
|
||||
// 关键优化1:取消任务后立即从队列移除,避免队列堆积
|
||||
((ScheduledThreadPoolExecutor) autoOffExecutor).setRemoveOnCancelPolicy(true);
|
||||
|
||||
// 关键优化2:允许核心线程超时回收,空闲时省资源
|
||||
((ScheduledThreadPoolExecutor) autoOffExecutor).setKeepAliveTime(60, TimeUnit.SECONDS);
|
||||
((ScheduledThreadPoolExecutor) autoOffExecutor).allowCoreThreadTimeOut(true);
|
||||
|
||||
log.info("自动关任务线程池初始化完成,核心线程数={}", corePoolSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 优雅关闭自动关任务线程池
|
||||
*/
|
||||
public void shutdownExecutor() {
|
||||
try {
|
||||
// 1. 取消所有未执行的自动关闭任务
|
||||
for (Map.Entry<String, ScheduledFuture<?>> entry : autoOffFutureMap.entrySet()) {
|
||||
entry.getValue().cancel(false);
|
||||
log.debug("【自动关任务】取消任务:{}", entry.getKey());
|
||||
}
|
||||
autoOffFutureMap.clear();
|
||||
// ✅ 停止时直接清空计数,避免残留
|
||||
autoOffDeviceCnt.clear();
|
||||
|
||||
// 2. 优雅关闭线程池
|
||||
if (autoOffExecutor != null) {
|
||||
autoOffExecutor.shutdown();
|
||||
try {
|
||||
// 等待3秒让任务完成
|
||||
if (!autoOffExecutor.awaitTermination(3, TimeUnit.SECONDS)) {
|
||||
// 强制关闭
|
||||
autoOffExecutor.shutdownNow();
|
||||
log.warn("【自动关任务】线程池强制关闭");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
autoOffExecutor.shutdownNow();
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
log.info("【自动关任务】线程池已关闭");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("【自动关任务】线程池关闭失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:是否存在该设备的自动关任务
|
||||
public boolean hasAutoOffTask(String deviceId) {
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
return false;
|
||||
}
|
||||
// ✅ O(1)查询,无需扫描整个任务表
|
||||
Integer cnt = autoOffDeviceCnt.get(deviceId);
|
||||
return cnt != null && cnt > 0;
|
||||
}
|
||||
|
||||
// 新增:自动关任务计数 +1(只维护deviceId维度,确保hasAutoOffTask为O(1))
|
||||
private void incAutoOffCnt(String deviceId) {
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
return;
|
||||
}
|
||||
autoOffDeviceCnt.merge(deviceId, 1, (a, b) -> a + b);
|
||||
}
|
||||
|
||||
// 新增:自动关任务计数 -1(避免负数;归零则清理key,省内存)
|
||||
private void decAutoOffCnt(String deviceId) {
|
||||
if (!StringUtils.hasText(deviceId)) {
|
||||
return;
|
||||
}
|
||||
autoOffDeviceCnt.compute(deviceId, (k, v) -> {
|
||||
if (v == null || v <= 1) {
|
||||
return null;
|
||||
}
|
||||
return v - 1;
|
||||
});
|
||||
}
|
||||
|
||||
// 改造:多线程执行自动关闭任务
|
||||
// 起个任务,固定多少秒-n秒,【监听最新的设备状态,如果还在运行】,发送设备关的指令
|
||||
public void scheduleAutoOff(String deviceId, String funcType, int delaySeconds) {
|
||||
|
||||
// ✅ 防御:避免极端情况下线程池尚未初始化导致NPE
|
||||
if (autoOffExecutor == null) {
|
||||
log.warn("【自动关任务】线程池未初始化,跳过创建任务:deviceId={}, funcType={}", deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
|
||||
String taskKey = "autooff:" + deviceId + ":" + funcType;
|
||||
|
||||
cancelAutoOff(deviceId,funcType);
|
||||
|
||||
// 使用多线程池提交任务
|
||||
ScheduledFuture<?> newFuture = autoOffExecutor.schedule(() -> {
|
||||
try {
|
||||
runAutoOff(deviceId, funcType);
|
||||
} catch (Exception e) {
|
||||
WxUtil.pushText("【自动关任务】提交任务失败! \n deviceId: "+deviceId+"\n funcType: "+funcType+"\n cause: "+e);
|
||||
log.error("【自动关任务】执行失败,deviceId={}, funcType={}", deviceId, funcType, e);
|
||||
} finally {
|
||||
// 任务执行完成后移除映射
|
||||
autoOffFutureMap.remove(taskKey);
|
||||
// ✅ 任务结束(成功/失败都算结束):减少该设备的“未完成任务数”,保证hasAutoOffTask准确
|
||||
decAutoOffCnt(deviceId);
|
||||
}
|
||||
}, delaySeconds, TimeUnit.SECONDS);
|
||||
|
||||
// 保存新任务的引用
|
||||
autoOffFutureMap.put(taskKey, newFuture);
|
||||
// ✅ 新任务创建成功:增加该设备的“未完成任务数”
|
||||
incAutoOffCnt(deviceId);
|
||||
log.info("【当前任务队列】:{}",autoOffDeviceCnt);
|
||||
log.info("【自动关任务】已创建(多线程):deviceId={}, funcType={}, delay={}s", deviceId, funcType, delaySeconds);
|
||||
}
|
||||
|
||||
// 自动关闭任务的核心逻辑(无改动)
|
||||
// 新增:读取最新状态(device:latest:{deviceId}),若仍为1则下发 {"funcType":0} 到 dtu/{id}/down
|
||||
private void runAutoOff(String deviceId, String funcType) throws MqttException {
|
||||
String latest = stringRedisTemplate.opsForValue().get("device:latest:" + deviceId);
|
||||
String skipReason = "";
|
||||
if (!StringUtils.hasText(latest)) {
|
||||
//todo
|
||||
log.warn("【自动关任务】无最新状态,跳过:deviceId={}, funcType={}", deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
JSONObject latestObj;
|
||||
try {
|
||||
latestObj = JSON.parseObject(latest);
|
||||
} catch (Exception e) {
|
||||
WxUtil.pushText("自动关任务执行报错-解析异常:\n deviceId: " + deviceId + "\n funcType:" + funcType+"\n Cause: "+e);
|
||||
log.warn("【自动关任务】最新状态JSON解析失败,跳过:deviceId={}, funcType={}", deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
if (latestObj == null || latestObj.isEmpty()) {
|
||||
log.info("【自动关任务】最新状态为空");
|
||||
skipReason = "【自动关任务】最新状态为空";
|
||||
return;
|
||||
}
|
||||
|
||||
// 设备每10秒上报的状态包:{"jm1k":0/1,...} 顶层字段直接取
|
||||
Integer current = null;
|
||||
String key = getKey(funcType);
|
||||
try {
|
||||
if (latestObj.containsKey(key)) {
|
||||
current = latestObj.getIntValue(key);
|
||||
}
|
||||
} catch (Exception ignore) {
|
||||
skipReason = "【自动关任务】最新状态功能码获取失败";
|
||||
}
|
||||
if (current == null) {
|
||||
skipReason = "【自动关任务】状态未知";
|
||||
}
|
||||
if (current != 1) {
|
||||
skipReason = "【自动关任务】未运行";
|
||||
}
|
||||
sysDevOperLogService.lambdaUpdate()
|
||||
.eq(SysDevOperLog::getImei, deviceId)
|
||||
.eq(SysDevOperLog::getFuncCode, funcType)
|
||||
.eq(SysDevOperLog::getOpType, 1)
|
||||
.eq(SysDevOperLog::getOpSource, 1)
|
||||
.eq(SysDevOperLog::getAckSuc, 1)
|
||||
.eq(SysDevOperLog::getIsTask, 1)
|
||||
.orderByDesc(SysDevOperLog::getCreateTime)
|
||||
.last("LIMIT 1")
|
||||
.set(SysDevOperLog::getExecResult,skipReason.isEmpty()?1:0)
|
||||
.set(SysDevOperLog::getUpdateBy,"自动关更新数据")
|
||||
.set(SysDevOperLog::getSkipReason, skipReason.isEmpty()?"执行成功":skipReason)
|
||||
.update();
|
||||
if (!skipReason.isEmpty()) {
|
||||
log.info("【自动关任务】检测未运行或状态未知,跳过关闭:deviceId={}, funcType={}, current={}", deviceId, funcType, current);
|
||||
return;
|
||||
}
|
||||
|
||||
// 新增:自动关也走分布式锁(避免与前端并发控制同一功能导致乱序/互相覆盖)
|
||||
String lockKey = "lock:" + deviceId + ":" + funcType;
|
||||
Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
|
||||
lockKey, "autooff", dtuCtlLockTTL, TimeUnit.SECONDS
|
||||
);
|
||||
if (lockSuccess == null || !lockSuccess) {
|
||||
log.info("【自动关任务】{}功能忙(锁占用),跳过自动关闭:deviceId={}, funcType={}", funcType, deviceId, funcType);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
String deviceTopic = "dtu/" + deviceId + "/down";
|
||||
JSONObject down = new JSONObject();
|
||||
down.put(funcType, 0);
|
||||
log.info("触发自动化条件");
|
||||
mqttMessageSender.publish(deviceTopic, down.toJSONString());
|
||||
saveDevLog(deviceId, funcType, down, latest);
|
||||
log.info("【自动关任务】检测仍在运行,已下发关闭:deviceId={}, funcType={}, payload={}", deviceId, funcType, down.toJSONString());
|
||||
} catch (Exception e){
|
||||
WxUtil.pushText("自动关任务执行报错-下发关闭指令:\n deviceId: " + deviceId + "\n funcType:" + funcType+"\n Cause: "+e);
|
||||
log.warn("【自动关任务】下发关闭指令失败,跳过:deviceId={}, funcType={}", deviceId, funcType);
|
||||
} finally {
|
||||
stringRedisTemplate.delete(lockKey);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveDevLog(String deviceId, String funcType, JSONObject down, String latest) {
|
||||
SysAgriInfo agriInfo = sysAgriInfoService.lambdaQuery()
|
||||
.eq(SysAgriInfo::getImei, deviceId)
|
||||
.one();
|
||||
String agriName = (agriInfo != null && ObjectUtils.isNotEmpty(agriInfo.getAgriName())) ? agriInfo.getAgriName() : null;
|
||||
SysDevOperLog logDto = new SysDevOperLog();
|
||||
logDto.setAgriName(agriName);
|
||||
logDto.setImei(deviceId);
|
||||
logDto.setFuncCode(funcType);
|
||||
logDto.setOpType(0);
|
||||
logDto.setOpSource(2);
|
||||
logDto.setPayload(down.toJSONString());
|
||||
logDto.setLockAcquired(1);
|
||||
logDto.setLockHolder("autoOff");
|
||||
logDto.setExecResult(1);
|
||||
logDto.setLatestState(latest);
|
||||
logDto.setCreateBy("自动关");
|
||||
logDto.setTaskStatus(getFutureStatus().toString());
|
||||
sysDevOperLogService.save(logDto);
|
||||
}
|
||||
|
||||
// 新增:收到“关”指令时,尝试取消对应自动关任务(优化:减少无意义任务执行;正确性仍以到点状态判断为准)
|
||||
public void cancelAutoOff(String deviceId, String funcType) {
|
||||
if (!StringUtils.hasText(deviceId) || !StringUtils.hasText(funcType)) {
|
||||
return;
|
||||
}
|
||||
String taskKey = "autooff:" + deviceId + ":" + funcType;
|
||||
// 同设备同功能只保留最后一次任务:只有旧任务还没开始时才替换
|
||||
ScheduledFuture<?> oldFuture = autoOffFutureMap.get(taskKey);
|
||||
if (oldFuture != null) {
|
||||
log.info("存在定时任务:taskKey: "+taskKey);
|
||||
// cancel=false 说明任务已开始/已完成,避免双执行:不再创建新任务
|
||||
if (!oldFuture.cancel(false)) {
|
||||
return;
|
||||
}
|
||||
sysDevOperLogService.lambdaUpdate()
|
||||
.eq(SysDevOperLog::getImei, deviceId)
|
||||
.eq(SysDevOperLog::getFuncCode, funcType)
|
||||
.eq(SysDevOperLog::getOpType, 1)
|
||||
.eq(SysDevOperLog::getOpSource, 1)
|
||||
.eq(SysDevOperLog::getAckSuc, 1)
|
||||
.eq(SysDevOperLog::getIsTask, 1)
|
||||
.orderByDesc(SysDevOperLog::getCreateTime)
|
||||
.last("LIMIT 2")
|
||||
.set(SysDevOperLog::getExecResult,2)
|
||||
.set(SysDevOperLog::getLatestState, "{\"msg\":\"任务已退出\"}")
|
||||
.set(SysDevOperLog::getUpdateBy,"自动关")
|
||||
.set(SysDevOperLog::getSkipReason, "旧任务已退出")
|
||||
.update();
|
||||
// cancel成功:旧任务不会跑了,这时再remove并减计数
|
||||
autoOffFutureMap.remove(taskKey, oldFuture);
|
||||
decAutoOffCnt(deviceId);
|
||||
log.info("旧任务已退出:"+taskKey);
|
||||
} else {
|
||||
log.info("不存在定时任务:taskKey: "+taskKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否有当前imei的功能任务
|
||||
* 担忧点、、、、自动模式下,上一次指令运行时间过长,本次触发指令是否取消本次任务
|
||||
* 但是目前自动化任务改为10分钟一执行、前端运行时间也就是风口限制最大只允许运行5分钟,自动模式下也是不允许超过300秒
|
||||
* 因此按理说,此后应该不会出现此类问题
|
||||
* @param deviceId
|
||||
* @param funcType
|
||||
* @return
|
||||
*/
|
||||
public boolean isHaveTask(String deviceId, String funcType) {
|
||||
String taskKey = "autooff:" + deviceId + ":" + funcType;
|
||||
// 同设备同功能只保留最后一次任务:只有旧任务还没开始时才替换
|
||||
ScheduledFuture<?> oldFuture = autoOffFutureMap.get(taskKey);
|
||||
return oldFuture != null;
|
||||
}
|
||||
// 自动关是否启用(你可以先写死 true / false)
|
||||
public boolean isEnabled() {
|
||||
return true; // 之后可接配置
|
||||
}
|
||||
|
||||
// 线程池是否初始化
|
||||
public boolean isExecutorInited() {
|
||||
return autoOffExecutor != null;
|
||||
}
|
||||
|
||||
// 当前所有未完成任务数
|
||||
public int getTotalTaskCount() {
|
||||
return autoOffFutureMap.size();
|
||||
}
|
||||
|
||||
// 当前有自动关任务的设备数量
|
||||
public int getDeviceTaskCount() {
|
||||
return autoOffDeviceCnt.size();
|
||||
}
|
||||
|
||||
public JSONObject getFutureStatus() {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("isEnabled", true);
|
||||
json.put("isExecutorInited", autoOffExecutor != null);
|
||||
json.put("getTotalTaskCount", autoOffFutureMap.size());
|
||||
json.put("getDeviceTaskCount", autoOffDeviceCnt.size());
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
public String getKey(String funcType) {
|
||||
// 边界判断:避免空指针异常和字符串长度不足的异常
|
||||
if (funcType == null || funcType.length() <= 1) {
|
||||
return funcType == null ? null : "";
|
||||
}
|
||||
|
||||
// 截取:从索引0开始,到倒数第二位结束(substring的结束索引是开区间,不包含自身)
|
||||
return funcType.substring(0, funcType.length() - 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,345 +0,0 @@
|
|||
package com.agri.framework.manager;
|
||||
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.web.dispatcher.MqttMessageDispatcher;
|
||||
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
|
||||
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
|
||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
||||
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* MQTT客户端生命周期管理器
|
||||
* 核心功能:
|
||||
* 1. 订阅设备状态、前端控制指令主题
|
||||
* 2. MQTT客户端启动/停止/重连
|
||||
* 3. 管理自动关闭任务线程池
|
||||
* 4. 监听MQTT连接状态,设置消息回调
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class MqttClientManager implements SmartLifecycle {
|
||||
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(MqttClientManager.class);
|
||||
|
||||
/**
|
||||
* 新增:生命周期管理标识,控制MQTT客户端启动/关闭
|
||||
*/
|
||||
private final AtomicBoolean isRunning = new AtomicBoolean(false);
|
||||
|
||||
/**
|
||||
* MQTT客户端(由MqttConfig配置类注入)
|
||||
*/
|
||||
@Resource
|
||||
private MqttClient mqttClient;
|
||||
|
||||
/**
|
||||
* MQTT连接配置项(从MqttConfig注入)
|
||||
*/
|
||||
@Resource
|
||||
private MqttConnectOptions mqttConnectOptions;
|
||||
|
||||
/**
|
||||
* MQTT消息分发器,转发消息到对应处理器
|
||||
*/
|
||||
@Resource
|
||||
private MqttMessageDispatcher mqttMessageDispatcher;
|
||||
|
||||
/**
|
||||
* 自动关任务管理器,初始化/关闭线程池
|
||||
*/
|
||||
@Resource
|
||||
private MqttAutoOffManager mqttAutoOffManager;
|
||||
|
||||
// 读取配置文件中的默认订阅主题(移除心跳主题)
|
||||
@Value("${spring.mqtt.default-topic}")
|
||||
private String defaultTopic;
|
||||
|
||||
// 新增:自动关闭任务线程池核心线程数(可配置)
|
||||
@Value("${spring.mqtt.auto-off-thread-pool-size:5}")
|
||||
private int autoOffThreadPoolSize;
|
||||
|
||||
private final ThreadPoolExecutor mqttBizPool =
|
||||
new ThreadPoolExecutor(
|
||||
8, // core
|
||||
16, // max
|
||||
60, TimeUnit.SECONDS,
|
||||
new ArrayBlockingQueue<>(2000), // 有界、较小
|
||||
r -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setName("mqtt-biz-" + t.getId());
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
},
|
||||
new ThreadPoolExecutor.DiscardPolicy() // 直接丢
|
||||
);
|
||||
/**
|
||||
* 初始化:订阅主题+设置回调
|
||||
* (移除@PostConstruct,改为由SmartLifecycle的start()触发)
|
||||
* <p>
|
||||
* 【方案A】不做自写重连;Paho会在连接断开后自动重连(前提:connectOptions.setAutomaticReconnect(true))
|
||||
*/
|
||||
public void subscribeTopics() throws MqttException {
|
||||
// 关键补充1:判空
|
||||
if (mqttClient == null) {
|
||||
log.error("【MQTT初始化】客户端实例为空,无法订阅主题");
|
||||
throw new MqttException(MqttException.REASON_CODE_CLIENT_NOT_CONNECTED);
|
||||
}
|
||||
|
||||
// 解析配置的主题列表
|
||||
final String[] topicsFinal = Arrays.stream(defaultTopic.split(","))
|
||||
.map(String::trim).toArray(String[]::new);
|
||||
final int[] qosFinal = new int[topicsFinal.length];
|
||||
Arrays.fill(qosFinal, 0);
|
||||
|
||||
|
||||
// 设置MQTT消息回调:处理连接断开、消息接收、消息发布完成
|
||||
mqttClient.setCallback(new MqttCallbackExtended() {
|
||||
@Override
|
||||
public void connectComplete(boolean reconnect, String serverURI) {
|
||||
log.info("【MQTT连接完成】reconnect={}, serverURI={}, clientId={}",
|
||||
reconnect, serverURI, safeClientId());
|
||||
// cleanSession=true:重连后必须补订阅
|
||||
if (reconnect) {
|
||||
try {
|
||||
mqttClient.subscribe(topicsFinal, qosFinal);
|
||||
log.info("【MQTT订阅恢复】topicsFinal={}", String.join(",", topicsFinal));
|
||||
} catch (Exception e) {
|
||||
log.error("【MQTT订阅恢复失败】", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MQTT连接断开回调
|
||||
* @param cause 断开原因
|
||||
*/
|
||||
@Override
|
||||
public void connectionLost(Throwable cause) {
|
||||
log.info("autoReconnect={}, cleanSession={}, keepAlive={}",
|
||||
mqttConnectOptions.isAutomaticReconnect(),
|
||||
mqttConnectOptions.isCleanSession(),
|
||||
mqttConnectOptions.getKeepAliveInterval());
|
||||
|
||||
log.error("【MQTT连接异常】连接断开,clientId:{},原因:{}",
|
||||
safeClientId(), (cause == null ? "unknown" : cause.getMessage()), cause);
|
||||
WxUtil.pushText("【MQTT连接异常】连接断开:\n clientId:"+safeClientId()+"\n Cause: "+cause);
|
||||
// 【方案A】不再触发自写重连;Paho自动重连会接管重连过程
|
||||
// 这里只记录日志即可
|
||||
if (isRunning.get()) {
|
||||
log.warn("【MQTT自动重连】已开启automaticReconnect,等待Paho自动重连...");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 收到MQTT消息回调:核心处理入口
|
||||
* @param topic 消息主题
|
||||
* @param message 消息内容
|
||||
* @throws Exception 消息处理异常
|
||||
*/
|
||||
@Override
|
||||
public void messageArrived(String topic, MqttMessage message) throws Exception {
|
||||
|
||||
final String payload = new String(message.getPayload(), StandardCharsets.UTF_8);
|
||||
if (message.isRetained()) {
|
||||
log.info("ignore retained snapshot: {}", topic);
|
||||
return;
|
||||
}
|
||||
|
||||
mqttBizPool.execute(() -> {
|
||||
// log.debug("mqttBizPool active={}, queue={}",
|
||||
// mqttBizPool.getActiveCount(),
|
||||
// mqttBizPool.getQueue().size());
|
||||
if (mqttBizPool.getActiveCount()>10 || mqttBizPool.getQueue().size()>1000) {
|
||||
WxUtil.pushText("线程池繁忙! \n 正在处理中任务:"+mqttBizPool.getActiveCount()+"\n 剩余待进行任务:"+mqttBizPool.getQueue().size());
|
||||
}
|
||||
try {
|
||||
// 优化:显式指定UTF-8编码,避免乱码(JDK 8兼容)
|
||||
mqttMessageDispatcher.handleMessage(topic, payload);
|
||||
} catch (Exception e) {
|
||||
log.error("【MQTT消息处理异常】topic={}, payload={}", topic, payload, e);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 消息发布完成回调(仅日志记录,无业务逻辑)
|
||||
* @param token 发布令牌
|
||||
*/
|
||||
@Override
|
||||
public void deliveryComplete(IMqttDeliveryToken token) {
|
||||
if (token != null && token.getTopics() != null && token.getTopics().length > 0) {
|
||||
// log.info("【MQTT确认】消息发布完成,clientId:{},主题:{}", safeClientId(), token.getTopics()[0]);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!mqttClient.isConnected()) {
|
||||
try {
|
||||
// 使用注入的连接配置项连接Broker(带用户名密码、自动重连等配置)
|
||||
mqttClient.connect(mqttConnectOptions);
|
||||
log.info("【MQTT连接】客户端已成功连接到Broker,clientId:{}", mqttClient.getClientId());
|
||||
} catch (MqttException e) {
|
||||
log.error("【MQTT连接】连接Broker失败,clientId:{}", mqttClient.getClientId(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
// 订阅主题
|
||||
// connect 后首次订阅
|
||||
try {
|
||||
mqttClient.subscribe(topicsFinal, qosFinal);
|
||||
log.info("【MQTT初始化】订阅主题完成,clientId:{},topicsFinal={}",
|
||||
mqttClient.getClientId(), String.join(",", topicsFinal));
|
||||
} catch (MqttException e) {
|
||||
log.error("【MQTT初始化】订阅失败,clientId:{},topicsFinal={}",
|
||||
safeClientId(), String.join(",", topicsFinal), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private String safeClientId() {
|
||||
try {
|
||||
return (mqttClient == null ? "null" : mqttClient.getClientId());
|
||||
} catch (Exception e) {
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 手动重连接口(供Controller调用) ==========
|
||||
|
||||
/**
|
||||
* 手动触发MQTT重连(最小改动:不替换client实例,只用同一个client重连)
|
||||
*/
|
||||
public synchronized String manualReconnect() {
|
||||
isRunning.set(true);
|
||||
try {
|
||||
// 强制断开旧连接(如果存在)
|
||||
if (mqttClient != null && mqttClient.isConnected()) {
|
||||
mqttClient.disconnect();
|
||||
}
|
||||
// 重新初始化订阅(内部会connect + subscribe)
|
||||
subscribeTopics();
|
||||
log.info("【手动重连】MQTT客户端重连成功");
|
||||
return "MQTT手动重连成功";
|
||||
} catch (MqttException e) {
|
||||
log.error("【手动重连】MQTT客户端重连失败", e);
|
||||
return "MQTT手动重连失败:" + e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前MQTT连接状态
|
||||
*/
|
||||
public Map<String,Object> getMqttStatus() {
|
||||
boolean connected = (mqttClient != null && mqttClient.isConnected());
|
||||
String status = connected ? "已连接" : "已断开";
|
||||
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("enabled", mqttAutoOffManager.isEnabled());
|
||||
data.put("mqtt", status);
|
||||
data.put("clientId", safeClientId());
|
||||
data.put("executorInited", mqttAutoOffManager.isExecutorInited());
|
||||
data.put("totalTaskCount", mqttAutoOffManager.getTotalTaskCount());
|
||||
data.put("deviceTaskCount", mqttAutoOffManager.getDeviceTaskCount());
|
||||
return data;
|
||||
}
|
||||
|
||||
// ======================== SmartLifecycle 生命周期管理(核心修复) ========================
|
||||
|
||||
/**
|
||||
* 启动MQTT客户端(Spring上下文初始化/重启时触发)
|
||||
* 核心:替代@PostConstruct,保证上下文重启时重新初始化MQTT连接
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
log.info("开始监听");
|
||||
if (isRunning.compareAndSet(false, true)) {
|
||||
try {
|
||||
// 初始化自动关任务线程池
|
||||
mqttAutoOffManager.initExecutor(autoOffThreadPoolSize);
|
||||
// 核心修改:无论是否已连接,都执行订阅
|
||||
subscribeTopics();
|
||||
log.info("【MQTT生命周期】客户端启动成功(已设置回调+订阅主题),自动关闭任务线程池大小:{}", autoOffThreadPoolSize);
|
||||
} catch (MqttException e) {
|
||||
log.error("【MQTT生命周期】客户端启动失败", e);
|
||||
isRunning.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止MQTT客户端
|
||||
* 改造点:优化多线程池的优雅关闭
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
if (isRunning.compareAndSet(true, false)) {
|
||||
try {
|
||||
// 关闭自动关任务线程池
|
||||
mqttAutoOffManager.shutdownExecutor();
|
||||
// 关闭MQTT客户端
|
||||
if (mqttClient != null) {
|
||||
if (mqttClient.isConnected()) {
|
||||
mqttClient.disconnect();
|
||||
}
|
||||
mqttClient.close();
|
||||
log.info("【MQTT生命周期】客户端已优雅关闭");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("【MQTT生命周期】客户端关闭失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步停止
|
||||
*/
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断MQTT客户端是否运行中
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return isRunning.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动优先级(保证MQTT在Redis之后启动)
|
||||
*/
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否自动启动(默认true,Spring上下文初始化时自动调用start())
|
||||
*/
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,317 +0,0 @@
|
|||
package com.agri.framework.manager;
|
||||
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
import com.agri.common.utils.SecurityUtils;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.service.ISysUserService;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* MQTT订阅关系管理器
|
||||
* 核心功能:
|
||||
* 1. 维护前端-设备双向订阅关系(Redis)
|
||||
* 2. 前端单设备/全量设备订阅/取消订阅
|
||||
* 3. Redis批量操作(pipeline),提升性能
|
||||
* 4. 清理无效订阅关系,避免脏数据
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class MqttSubscriptionManager {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(MqttSubscriptionManager.class);
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Autowired
|
||||
private ISysUserService sysUserService;
|
||||
|
||||
/**
|
||||
* 农业信息服务,查询用户名下设备
|
||||
*/
|
||||
@Resource
|
||||
private ISysAgriInfoService agriInfoService;
|
||||
|
||||
// 新增:前端订阅关系TTL(兜底“取消订阅失败/异常退出”)——只维护subc:{clientId}的TTL
|
||||
@Value("${spring.mqtt.subc-ttl-seconds:3600}")
|
||||
private int subcTtlSeconds;
|
||||
|
||||
// 新增:pipeline 批量 SISMEMBER subc:{clientId} deviceId(N次->1次往返) 拿取失效的client
|
||||
public List<Boolean> pipeIsMemberSubc(List<String> clientIds, String deviceId) {
|
||||
if (clientIds == null || clientIds.isEmpty() || !StringUtils.hasText(deviceId)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// ✅ 关键:不发“占位命令”;只对有效clientId发SISMEMBER,同时保证返回结果与入参严格对齐
|
||||
int n = clientIds.size();
|
||||
// 创建长度n全部false的队列
|
||||
List<Boolean> out = new ArrayList<>(Collections.nCopies(n, Boolean.FALSE));
|
||||
List<Integer> idx = new ArrayList<>(n);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (StringUtils.hasText(clientIds.get(i))) {
|
||||
// 符合条件存进clientIds对应的索引
|
||||
idx.add(i);
|
||||
}
|
||||
}
|
||||
if (idx.isEmpty()) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// 处理每个每个clientId的值是否还在 值存在rs中 执行 stringRedisTemplate.executePipelined
|
||||
List<Object> rs = stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
|
||||
RedisSerializer<String> serializer = stringRedisTemplate.getStringSerializer();
|
||||
byte[] member = serializer.serialize(deviceId);
|
||||
for (int i : idx) {
|
||||
String clientId = clientIds.get(i);
|
||||
// 存放命令
|
||||
connection.sIsMember(serializer.serialize("subc:" + clientId), member);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
for (int j = 0; j < idx.size() && j < (rs == null ? 0 : rs.size()); j++) {
|
||||
out.set(idx.get(j), Boolean.TRUE.equals(rs.get(j)));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// 对应的subc不存在 删除对应的sub pipeline 批量 SREM sub:{deviceId} clientId(清理残留 N次->1次往返)
|
||||
public void pipeSRemSub(String deviceId, List<String> staleClientIds) {
|
||||
if (!StringUtils.hasText(deviceId) || staleClientIds == null || staleClientIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
stringRedisTemplate.executePipelined((RedisCallback<Object>) connection -> {
|
||||
RedisSerializer<String> serializer = stringRedisTemplate.getStringSerializer();
|
||||
byte[] subKey = serializer.serialize("sub:" + deviceId);
|
||||
for (String clientId : staleClientIds) {
|
||||
if (StringUtils.hasText(clientId)) {
|
||||
connection.sRem(subKey, serializer.serialize(clientId));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端订阅设备(Controller调用)
|
||||
*/
|
||||
public void subscribeDevice(String clientId, String deviceId) {
|
||||
if (!StringUtils.hasText(clientId) || !StringUtils.hasText(deviceId)) {
|
||||
log.error("【订阅管理】clientId或deviceId不能为空");
|
||||
throw new IllegalArgumentException("clientId和deviceId不能为空");
|
||||
}
|
||||
|
||||
// 保存订阅关系到Redis
|
||||
stringRedisTemplate.opsForSet().add("sub:" + deviceId, clientId);
|
||||
stringRedisTemplate.opsForSet().add("subc:" + clientId, deviceId);
|
||||
|
||||
// 新增:订阅成功后给subc设置TTL(兜底“取消订阅失败/异常退出”)
|
||||
stringRedisTemplate.expire("subc:" + clientId, subcTtlSeconds, TimeUnit.SECONDS);
|
||||
|
||||
log.info("【订阅管理】前端{}订阅设备{}成功", clientId, deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端取消订阅设备状态接口(供Controller层调用)
|
||||
* 逻辑:从设备的订阅列表移除前端clientId
|
||||
*
|
||||
* @param clientId 前端唯一标识
|
||||
* @param deviceId 设备ID
|
||||
*/
|
||||
public void unsubscribeDevice(String clientId, String deviceId) {
|
||||
if (!StringUtils.hasText(clientId) || !StringUtils.hasText(deviceId)) {
|
||||
log.error("【前端取消订阅】clientId或deviceId不能为空");
|
||||
throw new IllegalArgumentException("clientId和deviceId不能为空");
|
||||
}
|
||||
|
||||
// 从Redis删除订阅关系
|
||||
stringRedisTemplate.opsForSet().remove("sub:" + deviceId, clientId);
|
||||
stringRedisTemplate.opsForSet().remove("subc:" + clientId, deviceId);
|
||||
log.info("【前端取消订阅】前端{}取消订阅设备{}成功", clientId, deviceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量订阅:前端订阅指定用户名下的所有设备(Controller调用)
|
||||
* @param clientId 前端唯一标识(如web_001、app_002)
|
||||
* @return 订阅成功的设备数量
|
||||
*/
|
||||
public int subscribeAllDeviceByUserId(String clientId) {
|
||||
// 1. 入参校验
|
||||
if (!StringUtils.hasText(clientId)) {
|
||||
log.error("【全量订阅】clientId不能为空");
|
||||
throw new IllegalArgumentException("clientId不能为空");
|
||||
}
|
||||
|
||||
|
||||
// 2. Redis连接可用性校验
|
||||
try {
|
||||
stringRedisTemplate.hasKey("test:connection");
|
||||
} catch (Exception e) {
|
||||
log.warn("【全量订阅】Redis连接不可用,订阅操作跳过:{}", e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
Long userId = SecurityUtils.getLoginUser().getUserId();
|
||||
boolean update = sysUserService.lambdaUpdate()
|
||||
.eq(SysUser::getUserId, userId)
|
||||
.set(SysUser::getClientId, clientId)
|
||||
.update();
|
||||
if (update) {
|
||||
log.info("【全量订阅】用户端mqtt客户端绑定成功!");
|
||||
}
|
||||
|
||||
// 3. 查询该用户名下的所有设备ID(替换为你的实际设备查询逻辑)
|
||||
List<String> deviceIds = new ArrayList<>(agriInfoService.queryImeiByUserId(userId));
|
||||
if (userId == 1) {
|
||||
deviceIds.add("862538065276061");
|
||||
}
|
||||
if (deviceIds == null || deviceIds.isEmpty()) {
|
||||
log.warn("【全量订阅】用户{}名下无可用设备", userId);
|
||||
return 0;
|
||||
}
|
||||
// 过滤空设备ID,避免无效操作
|
||||
List<String> validDeviceIds = deviceIds.stream()
|
||||
.filter(StringUtils::hasText)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
if (validDeviceIds.isEmpty()) {
|
||||
log.warn("【全量订阅】用户{}名下无有效设备ID", userId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 4. 批量写入Redis订阅关系(兼容JDK 8的RedisCallback写法)
|
||||
try {
|
||||
stringRedisTemplate.execute(new RedisCallback<Void>() {
|
||||
@Override
|
||||
public Void doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
// 获取String序列化器(和stringRedisTemplate保持一致)
|
||||
RedisSerializer<String> serializer = stringRedisTemplate.getStringSerializer();
|
||||
|
||||
// 开启Redis事务
|
||||
connection.multi();
|
||||
byte[] clientIdBytes = serializer.serialize(clientId);
|
||||
// 4.1 设备→前端:给每个设备的订阅集合添加clientId
|
||||
for (String deviceId : validDeviceIds) {
|
||||
byte[] subKey = serializer.serialize("sub:" + deviceId);
|
||||
connection.sAdd(subKey, clientIdBytes);
|
||||
}
|
||||
|
||||
// 4.2 前端→设备:给前端的订阅集合批量添加所有设备ID
|
||||
byte[] subcKey = serializer.serialize("subc:" + clientId);
|
||||
byte[][] deviceIdBytesArray = new byte[validDeviceIds.size()][];
|
||||
for (int i = 0; i < validDeviceIds.size(); i++) {
|
||||
deviceIdBytesArray[i] = serializer.serialize(validDeviceIds.get(i));
|
||||
}
|
||||
connection.sAdd(subcKey, deviceIdBytesArray);
|
||||
|
||||
// 新增:给subc设置TTL(兜底“取消订阅失败/异常退出”)
|
||||
connection.expire(subcKey, subcTtlSeconds);
|
||||
|
||||
// 执行事务
|
||||
connection.exec();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
log.info("【全量订阅】前端{}成功订阅用户{}名下的{}个设备,设备列表:{}",
|
||||
clientId, userId, validDeviceIds.size(), validDeviceIds);
|
||||
return validDeviceIds.size();
|
||||
} catch (Exception e) {
|
||||
log.error("【全量------订阅】前端{}订阅用户{}名下设备失败", clientId, userId, e);
|
||||
throw new RuntimeException("全量订阅失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量取消:前端取消订阅的所有设备(即用户名下所有设备)
|
||||
* @param clientId 前端唯一标识
|
||||
* @return 需要前端取消监听的MQTT主题列表
|
||||
*/
|
||||
public List<String> unsubscribeAllDevice(String clientId) {
|
||||
// 1. 入参校验
|
||||
if (!StringUtils.hasText(clientId)) {
|
||||
log.error("【全量取消】clientId不能为空");
|
||||
throw new IllegalArgumentException("clientId不能为空");
|
||||
}
|
||||
|
||||
// 2. Redis连接可用性校验
|
||||
try {
|
||||
stringRedisTemplate.hasKey("test:connection");
|
||||
} catch (Exception e) {
|
||||
log.warn("【全量取消】Redis连接不可用,取消操作跳过:{}", e.getMessage());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 3. 查询该前端订阅的所有设备ID(即用户名下所有设备)
|
||||
Set<String> deviceSet = stringRedisTemplate.opsForSet().members("subc:" + clientId);
|
||||
if (deviceSet == null || deviceSet.isEmpty()) {
|
||||
log.warn("【全量取消】前端{}无订阅的设备", clientId);
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 4. 构建需要取消的MQTT主题列表
|
||||
List<String> frontendTopics = new ArrayList<>();
|
||||
for (String deviceId : deviceSet) {
|
||||
frontendTopics.add("frontend/" + clientId + "/dtu/" + deviceId + "/listener");
|
||||
}
|
||||
|
||||
// 5. 批量删除Redis订阅关系(兼容JDK 8的RedisCallback写法)
|
||||
try {
|
||||
stringRedisTemplate.execute(new RedisCallback<Void>() {
|
||||
@Override
|
||||
public Void doInRedis(RedisConnection connection) throws DataAccessException {
|
||||
RedisSerializer<String> serializer = stringRedisTemplate.getStringSerializer();
|
||||
|
||||
// 开启事务
|
||||
connection.multi();
|
||||
byte[] clientIdBytes = serializer.serialize(clientId);
|
||||
// 5.1 批量删除设备→前端的订阅关系
|
||||
for (String deviceId : deviceSet) {
|
||||
byte[] subKey = serializer.serialize("sub:" + deviceId);
|
||||
connection.sRem(subKey, clientIdBytes);
|
||||
}
|
||||
|
||||
// 5.2 删除前端→设备的反向索引(核心:清空该前端的所有订阅设备)
|
||||
byte[] subcKey = serializer.serialize("subc:" + clientId);
|
||||
connection.del(subcKey);
|
||||
|
||||
// 执行事务
|
||||
connection.exec();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("【全量取消】Redis批量删除失败", e);
|
||||
throw new RuntimeException("全量取消订阅失败:" + e.getMessage());
|
||||
}
|
||||
log.info("【全量取消】前端{}成功取消{}个设备的订阅", clientId, deviceSet.size());
|
||||
return frontendTopics;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package com.agri.framework.web.dispatcher;
|
||||
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.interceptor.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* MQTT消息分发器
|
||||
* 核心功能:根据Topic类型路由消息到对应处理器
|
||||
* 适配JDK 8,无心跳包相关逻辑
|
||||
*/
|
||||
@Component
|
||||
public class MqttMessageDispatcher {
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(MqttMessageDispatcher.class);
|
||||
|
||||
/**
|
||||
* 设备状态处理器
|
||||
*/
|
||||
@Resource
|
||||
private DeviceStatusHandler deviceStatusHandler;
|
||||
|
||||
/**
|
||||
* 前端控制指令处理器
|
||||
*/
|
||||
@Resource
|
||||
private FrontendControlHandler frontendControlHandler;
|
||||
|
||||
/**
|
||||
* 前端在线心跳处理器
|
||||
*/
|
||||
@Resource
|
||||
private FrontendOnlineHandler frontendOnlineHandler;
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
/**
|
||||
* 前端在线心跳处理器
|
||||
*/
|
||||
@Resource
|
||||
private FrontendConfigHandler frontendConfigHandler;
|
||||
|
||||
/**
|
||||
* 消息分发处理:根据主题类型路由到不同处理方法
|
||||
* 可以监听到设备传过来的业务数据 以及前端传过来的控制设备指令
|
||||
*
|
||||
* @param topic 消息主题
|
||||
* @param payload 消息内容(JSON字符串)
|
||||
*/
|
||||
public void handleMessage(String topic, String payload) {
|
||||
try {
|
||||
// log.info("【MQTT接收】topic={}, payload={}", topic, payload);
|
||||
if (env.acceptsProfiles("dev")) return;
|
||||
// 设备状态主题:dtu/{deviceId}/up
|
||||
if (topic.matches("dtu/\\w+/\\w+")) {
|
||||
deviceStatusHandler.handle(topic, payload);
|
||||
}
|
||||
// 处理前端控制指令主题:frontend/{clientId}/control/{deviceId}
|
||||
else if (topic.matches("frontend/\\w+/control/\\w+")) {
|
||||
frontendControlHandler.handle(topic, payload);
|
||||
}
|
||||
// 新增:前端在线心跳主题:frontend/{clientId}/online
|
||||
else if (topic.matches("frontend/\\w+/online")) {
|
||||
frontendOnlineHandler.handle(topic, payload);
|
||||
} // 新增:前端在线心跳主题:frontend/{clientId}/online
|
||||
else if (topic.matches("frontend/\\w+/\\w+/config")) {
|
||||
frontendConfigHandler.handle(topic, payload);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
WxUtil.pushText("【MQTT消息处理异常】\n topic: "+ topic+"\n cause: "+e);
|
||||
log.error("【MQTT消息处理异常】topic={}", topic, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ public class SysRegisterService
|
|||
*/
|
||||
public String register(RegisterBody registerBody)
|
||||
{
|
||||
String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword(),phonenumber = registerBody.getPhonenumber();
|
||||
String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
|
||||
SysUser sysUser = new SysUser();
|
||||
sysUser.setUserName(username);
|
||||
|
||||
|
|
@ -56,14 +56,6 @@ public class SysRegisterService
|
|||
{
|
||||
msg = "用户名不能为空";
|
||||
}
|
||||
else if (StringUtils.isEmpty(phonenumber))
|
||||
{
|
||||
msg = "用户手机号不能为空";
|
||||
}
|
||||
else if (phonenumber.length() != 11)
|
||||
{
|
||||
msg = "手机号必须为11位";
|
||||
}
|
||||
else if (StringUtils.isEmpty(password))
|
||||
{
|
||||
msg = "用户密码不能为空";
|
||||
|
|
@ -87,17 +79,7 @@ public class SysRegisterService
|
|||
sysUser.setNickName(username);
|
||||
sysUser.setPwdUpdateDate(DateUtils.getNowDate());
|
||||
sysUser.setPassword(SecurityUtils.encryptPassword(password));
|
||||
// todo 默认用户部 考虑项目启动将所有部门和角色缓存到redis中,修改时更新缓存
|
||||
sysUser.setDeptId(203L);
|
||||
sysUser.setPhonenumber(registerBody.getPhonenumber());
|
||||
if (userService.checkPhoneUnique(sysUser))
|
||||
{
|
||||
msg = "当前手机号已被绑定!";
|
||||
return msg;
|
||||
}
|
||||
boolean regFlag = userService.registerUser(sysUser);
|
||||
// 默认普通角色
|
||||
userService.insertUserAuth(sysUser.getUserId(), new Long[] {2L});
|
||||
if (!regFlag)
|
||||
{
|
||||
msg = "注册失败,请联系系统管理人员";
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@
|
|||
<version>3.5.3.1</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类 -->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.20</version> <!-- 该版本完全兼容JDK 8 -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
|
|
|||
|
|
@ -34,15 +34,7 @@
|
|||
<groupId>com.agri</groupId>
|
||||
<artifactId>agri-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agri</groupId>
|
||||
<artifactId>agri-system</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.agri</groupId>
|
||||
<artifactId>agri-framework</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
package com.agri.quartz.task;
|
||||
|
||||
import com.agri.framework.interceptor.FrontendControlHandler;
|
||||
import com.agri.framework.manager.AgriStatusManager;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
import com.agri.system.service.AgriService;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 在线状态监测 告警和离线
|
||||
*/
|
||||
@Component
|
||||
public class AgriStatusTask {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AgriStatusTask.class);
|
||||
|
||||
// Redis 前缀常量
|
||||
private static final String SUB_KEY_PREFIX = "sub:";
|
||||
private static final String LOCK_KEY = "lock:device:online:push";
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl:60}")
|
||||
private int lockTtl;
|
||||
|
||||
@Autowired
|
||||
private ISysAgriInfoService agriInfoService;
|
||||
|
||||
@Autowired
|
||||
private AgriStatusManager agriStatusManager;
|
||||
@Autowired
|
||||
private AgriService agriService;
|
||||
|
||||
@Resource
|
||||
private FrontendControlHandler frontendControlHandler;
|
||||
|
||||
/**
|
||||
* 定时任务:每10秒执行一次
|
||||
* 1. 扫描所有 sub: 开头的 key,提取 IMEI
|
||||
* 2. 批量查询设备在线状态
|
||||
* 3. 异步批量推送在线状态到 MQTT 主题 frontend/{imei}/online
|
||||
*/
|
||||
public void pushDeviceStatus() {
|
||||
// 1. 加分布式锁,避免集群重复执行
|
||||
Boolean lockSuccess = stringRedisTemplate.opsForValue()
|
||||
.setIfAbsent(LOCK_KEY, "running", lockTtl, TimeUnit.SECONDS);
|
||||
|
||||
// 补充:处理Redis连接异常的情况
|
||||
if (lockSuccess == null) {
|
||||
log.error("获取分布式锁失败:Redis连接异常");
|
||||
return;
|
||||
}
|
||||
if (!lockSuccess) {
|
||||
log.debug("其他节点正在执行,跳过本次推送");
|
||||
return;
|
||||
}
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
|
||||
// 查询大棚列表所有在线设备
|
||||
List<SysAgriInfo> agriInfos = agriInfoService.findAgriByUser(new SysAgriInfo());
|
||||
List<String> imeiList = agriService.queryAllGreenhouseImei(agriInfos);
|
||||
if (imeiList.isEmpty()) {
|
||||
log.info("大棚表无数据,结束推送");
|
||||
return;
|
||||
}
|
||||
Map<String, Map<String, Boolean>> statusMap
|
||||
= agriStatusManager.batchCheckDeviceOnline(imeiList);
|
||||
// 3. 首页状态
|
||||
agriStatusManager.asyncBatchPushMqtt(statusMap);
|
||||
// 4. 离线设备
|
||||
List<SysAgriInfo> offlineDevices = findOfflineDevices(agriInfos, statusMap);
|
||||
if (offlineDevices.isEmpty()) return;
|
||||
// 5. 保存消息中心
|
||||
List<SysMessage> messages = agriService.saveMessage(offlineDevices);
|
||||
// 6. 发送告警消息
|
||||
frontendControlHandler.sendAlarmMessage(messages);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("设备在线状态推送任务异常", e);
|
||||
// 可选:异常告警(如企业微信/钉钉)
|
||||
// WxUtil.pushText("【设备在线状态推送异常】\n" + e.getMessage());
|
||||
} finally {
|
||||
// 释放锁(可选,也可依赖TTL自动过期)
|
||||
stringRedisTemplate.delete(LOCK_KEY);
|
||||
}
|
||||
}
|
||||
// 查找离线设备
|
||||
private List<SysAgriInfo> findOfflineDevices(List<SysAgriInfo> agriInfos,
|
||||
Map<String, Map<String, Boolean>> statusMap) {
|
||||
if (statusMap.isEmpty()) {
|
||||
log.info("不存在任何imei");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
Map<String, Object> offlineMap = new HashMap<>();
|
||||
for (Map.Entry<String, Map<String, Boolean>> map : statusMap.entrySet()) {
|
||||
if (!map.getValue().get("imeiOnline")) {
|
||||
offlineMap.put(map.getKey(), map.getValue());
|
||||
}
|
||||
}
|
||||
if (offlineMap.isEmpty()) return new ArrayList<>();
|
||||
List<SysAgriInfo> offlineDevices = new ArrayList<>();
|
||||
for (SysAgriInfo agriInfo : agriInfos) {
|
||||
if (offlineMap.containsKey(agriInfo.getImei())) {
|
||||
agriInfo.setTitle("设备离线告警");
|
||||
agriInfo.setMsg("怀疑设备离线!请及时检查");
|
||||
offlineDevices.add(agriInfo);
|
||||
log.info("设备{} 不存在设备状态", agriInfo.getImei());
|
||||
}
|
||||
}
|
||||
return offlineDevices;
|
||||
}
|
||||
|
||||
/*
|
||||
* 企业级Lua方案:基于大棚表IMEI列表,批量查sub:{imei}是否存在
|
||||
* 核心:1次Redis网络往返完成所有查询,极致性能 + 数据合法
|
||||
* @return 合法大棚IMEI的在线状态(key=IMEI,value=是否在线)
|
||||
*/
|
||||
public Map<String, Boolean> getGreenhouseOnlineStatusByLua() {
|
||||
// 1. 从大棚表获取所有合法IMEI
|
||||
List<String> allGreenhouseImeiList = agriInfoService.queryImeiByUserId(null);
|
||||
if (allGreenhouseImeiList.isEmpty()) {
|
||||
log.info("大棚表无合法IMEI,返回空");
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
// 2. 简化版Lua脚本(批量查sub:{imei}是否存在)
|
||||
String luaScript = "" +
|
||||
"local imeiList = ARGV\n" +
|
||||
"local prefix = KEYS[1]\n" +
|
||||
"local result = {}\n" +
|
||||
"for _, imei in ipairs(imeiList) do\n" +
|
||||
" local key = prefix .. imei\n" +
|
||||
" local isOnline = redis.call('EXISTS', key)\n" +
|
||||
" table.insert(result, imei)\n" +
|
||||
" table.insert(result, tostring(isOnline))\n" +
|
||||
"end\n" +
|
||||
"return result";
|
||||
|
||||
// ===== 核心修改:保留你指定的写法,仅做JDK 8兼容 =====
|
||||
DefaultRedisScript<List> redisScript = new DefaultRedisScript<>();
|
||||
redisScript.setScriptText(luaScript);
|
||||
redisScript.setResultType(List.class); // 保留原有写法
|
||||
|
||||
// 3. 构造参数
|
||||
List<String> keys = Collections.singletonList(SUB_KEY_PREFIX);
|
||||
List<String> args = allGreenhouseImeiList;
|
||||
|
||||
try {
|
||||
// 4. 执行脚本(JDK 8 强制类型转换,安全兼容)
|
||||
List resultList = stringRedisTemplate.execute(redisScript, keys, args.toArray(new String[0]));
|
||||
|
||||
// 5. 解析结果(兼容JDK 8 原始List类型)
|
||||
Map<String, Boolean> onlineStatusMap = new HashMap<>();
|
||||
if (resultList != null && resultList.size() >= 2) {
|
||||
for (int i = 0; i < resultList.size(); i += 2) {
|
||||
// JDK 8 显式转换为String,避免类型异常
|
||||
String imei = String.valueOf(resultList.get(i));
|
||||
String isOnlineStr = String.valueOf(resultList.get(i + 1));
|
||||
onlineStatusMap.put(imei, "1".equals(isOnlineStr));
|
||||
}
|
||||
}
|
||||
|
||||
return onlineStatusMap;
|
||||
} catch (Exception e) {
|
||||
log.error("Lua脚本执行失败", e);
|
||||
return new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ========== 方式1:用 ScanCursor 遍历 sub:* Key ==========
|
||||
private List<String> scanAllSubDeviceImei() {
|
||||
List<String> imeiList = new ArrayList<>();
|
||||
// count 建议一次扫描1000个槽位
|
||||
ScanOptions scanOptions = ScanOptions.scanOptions()
|
||||
.match(SUB_KEY_PREFIX + "*")
|
||||
.count(1000)
|
||||
.build();
|
||||
|
||||
// JDK 8 需显式声明 Cursor<byte[]> 泛型,try-with-resources 自动关闭游标
|
||||
try (Cursor<byte[]> cursor = stringRedisTemplate.getConnectionFactory()
|
||||
.getConnection()
|
||||
.scan(scanOptions)) {
|
||||
|
||||
while (cursor.hasNext()) {
|
||||
byte[] keyBytes = cursor.next();
|
||||
String key = new String(keyBytes, StandardCharsets.UTF_8);
|
||||
if (key.startsWith(SUB_KEY_PREFIX)) {
|
||||
String imei = key.substring(SUB_KEY_PREFIX.length());
|
||||
imeiList.add(imei);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Cursor 扫描 sub: 前缀 key 失败", e);
|
||||
}
|
||||
return imeiList;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
package com.agri.quartz.task;
|
||||
|
||||
import com.agri.common.utils.spring.SpringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Component("agriTask")
|
||||
public class AgriTask {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AgriTask.class);
|
||||
|
||||
public void clearInvalidCache() {
|
||||
log.info("=============【定时任务】开始执行Redis sub: 键清理任务=============");
|
||||
int deletedCount = 0;
|
||||
|
||||
try {
|
||||
// 重点*****
|
||||
RedisTemplate<String, Object> redisTemplate = SpringUtils.getBean("redisTemplate");
|
||||
if (redisTemplate == null) {
|
||||
log.error("RedisTemplate 获取失败,清理任务终止");
|
||||
return;
|
||||
}
|
||||
|
||||
ScanOptions scanOptions = ScanOptions.scanOptions()
|
||||
.match("sub:*")
|
||||
.count(1000)
|
||||
.build();
|
||||
|
||||
Cursor<byte[]> cursor = redisTemplate.executeWithStickyConnection(connection ->
|
||||
connection.scan(scanOptions)
|
||||
);
|
||||
|
||||
List<String> batchKeys = new ArrayList<>(1000);
|
||||
|
||||
while (cursor != null && cursor.hasNext()) {
|
||||
byte[] keyBytes = cursor.next();
|
||||
String key = new String(keyBytes, StandardCharsets.UTF_8);
|
||||
batchKeys.add(key);
|
||||
|
||||
if (batchKeys.size() >= 1000) {
|
||||
deletedCount += batchKeys.size();
|
||||
redisTemplate.delete(batchKeys);
|
||||
log.info("批量删除 {} 个sub: 键", batchKeys.size());
|
||||
batchKeys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!batchKeys.isEmpty()) {
|
||||
deletedCount += batchKeys.size();
|
||||
redisTemplate.delete(batchKeys);
|
||||
log.info("批量删除剩余 {} 个sub: 键", batchKeys.size());
|
||||
}
|
||||
|
||||
if (cursor != null) {
|
||||
try {
|
||||
cursor.close();
|
||||
} catch (Exception e) {
|
||||
log.error("关闭 Redis 游标失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("=============【定时任务】Redis sub: 键清理完成,总计删除 {} 个键=============", deletedCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("=============【定时任务】Redis sub: 键清理失败=============", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
package com.agri.quartz.task;
|
||||
|
||||
import com.agri.framework.interceptor.FrontendControlHandler;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
import com.agri.system.service.AgriService;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.service.ISysDtuDataService;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class AgriTempTask {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AgriTempTask.class);
|
||||
|
||||
@Autowired
|
||||
private ISysDtuDataService dtuDataService;
|
||||
|
||||
@Autowired
|
||||
private ISysAgriInfoService agriInfoService;
|
||||
|
||||
private static final String LOCK_KEY = "lock:check:temp:push";
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl:60}")
|
||||
private int lockTtl;
|
||||
|
||||
@Autowired
|
||||
private AgriService agriService;
|
||||
|
||||
@Resource
|
||||
private FrontendControlHandler frontendControlHandler;
|
||||
|
||||
public void checkTempStatus() {
|
||||
if (!acquireLock()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
List<SysAgriInfo> agriInfos = agriInfoService.findAgriByUser(new SysAgriInfo());
|
||||
List<String> imeiList = agriService.queryAllGreenhouseImei(agriInfos);
|
||||
if (CollectionUtils.isEmpty(imeiList)) {
|
||||
log.info("大棚表无数据,结束推送");
|
||||
return;
|
||||
}
|
||||
Map<String, Object> latestDataMap = queryLatestDtuData(imeiList);
|
||||
List<SysAgriInfo> offlineDevices = findOfflineDevices(agriInfos, latestDataMap);
|
||||
if (CollectionUtils.isEmpty(offlineDevices)) return;
|
||||
|
||||
List<SysMessage> messages = agriService.saveMessage(offlineDevices);
|
||||
// 推送离线告警
|
||||
frontendControlHandler.sendAlarmMessage(messages);
|
||||
} catch (Exception e) {
|
||||
log.error("设备在线状态推送任务异常", e);
|
||||
} finally {
|
||||
releaseLock();
|
||||
}
|
||||
}
|
||||
// 获取分布式锁
|
||||
private boolean acquireLock() {
|
||||
Boolean lockSuccess = stringRedisTemplate.opsForValue()
|
||||
.setIfAbsent(LOCK_KEY, "agriTempTask", lockTtl, TimeUnit.SECONDS);
|
||||
if (lockSuccess == null) {
|
||||
log.error("获取分布式锁失败:Redis连接异常");
|
||||
return false;
|
||||
}
|
||||
if (!lockSuccess) {
|
||||
log.debug("其他节点正在执行,跳过本次推送");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 释放分布式锁
|
||||
private void releaseLock() {
|
||||
stringRedisTemplate.delete(LOCK_KEY);
|
||||
}
|
||||
|
||||
|
||||
// 查询所有大棚的最新温湿度数据
|
||||
private Map<String, Object> queryLatestDtuData(List<String> imeiList) {
|
||||
List<Map<String, Object>> dtuDataList = dtuDataService.getLastDtuDataByImeiList(imeiList);
|
||||
Map<String, Object> dataMap = new HashMap<>();
|
||||
if (CollectionUtils.isEmpty(dtuDataList)) {
|
||||
return dataMap;
|
||||
}
|
||||
for (Map<String, Object> item : dtuDataList) {
|
||||
Object imei = item.get("imei");
|
||||
if (imei != null) {
|
||||
dataMap.put(imei.toString(), item);
|
||||
}
|
||||
}
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
// 查找离线设备
|
||||
private List<SysAgriInfo> findOfflineDevices(List<SysAgriInfo> agriInfos,
|
||||
Map<String, Object> latestDataMap) {
|
||||
if (CollectionUtils.isEmpty(agriInfos)) {
|
||||
return agriInfos;
|
||||
}
|
||||
List<SysAgriInfo> offlineList = new ArrayList<>();
|
||||
for (SysAgriInfo agriInfo : agriInfos) {
|
||||
if (!latestDataMap.containsKey(agriInfo.getImei())) {
|
||||
agriInfo.setTitle("温度离线");
|
||||
agriInfo.setMsg("怀疑温度离线!请检查");
|
||||
offlineList.add(agriInfo);
|
||||
log.info("设备{} 不存在温湿度数据", agriInfo.getImei());
|
||||
}
|
||||
}
|
||||
return offlineList;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,467 +0,0 @@
|
|||
package com.agri.quartz.task;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.agri.common.enums.TempCommandStatus;
|
||||
import com.agri.common.utils.*;
|
||||
import com.agri.common.utils.wechat.WxUtil;
|
||||
import com.agri.framework.config.MqttConfig;
|
||||
import com.agri.framework.manager.MqttAutoOffManager;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysAgriLimit;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
import com.agri.system.domain.SysImeiAutoLog;
|
||||
import com.agri.system.domain.vo.RollerTermVO;
|
||||
import com.agri.system.service.*;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.eclipse.paho.client.mqttv3.MqttException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 卷膜自动模式定时检查
|
||||
* 每五分钟执行一次 每日时间区间内执行
|
||||
* 1、查询大棚列表开启自动模式的大棚,获取imei
|
||||
* 2、根据imei查询dtu_data最后一分钟最后一条温度数据
|
||||
* 3、查询参数设置获取 风口总长 预留风口长度 在条件内开启指定风口,第一次开 预留风口+条件内设定的风口长度 还是得存日志、、、
|
||||
* 4、下发开启或者关闭指令 起个自动关任务 需要改自动关逻辑,自动模式,监听处不转发回执
|
||||
* todo通知用户
|
||||
*/
|
||||
@Component("rollerAutoTask")
|
||||
public class RollerAutoTask {
|
||||
|
||||
/**
|
||||
* 优化:统一使用SLF4J日志(JDK 8兼容)
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(RollerAutoTask.class);
|
||||
|
||||
@Autowired
|
||||
private ISysAgriInfoService agriInfoService;
|
||||
|
||||
@Autowired
|
||||
private ISysDtuDataService dtuDataService;
|
||||
|
||||
@Autowired
|
||||
private ISysRollerParamService rollerParamService;
|
||||
|
||||
@Resource
|
||||
private MqttConfig.MqttMessageSender mqttMessageSender;
|
||||
|
||||
@Autowired
|
||||
private ISysDevOperLogService devOperLogService;
|
||||
|
||||
@Autowired
|
||||
private MqttAutoOffManager autoOffManager;
|
||||
|
||||
/**
|
||||
* Redis模板,用于存储订阅关系、设备在线状态、分布式锁
|
||||
*/
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
|
||||
@Autowired
|
||||
private ISysAgriLimitService agriLimitService;
|
||||
|
||||
|
||||
@Value("${spring.mqtt.dtu-ctl-lock-ttl}")
|
||||
private int dtuCtlLockTTL;
|
||||
|
||||
@Autowired
|
||||
private ISysImeiAutoLogService imeiAutoLogService;
|
||||
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
|
||||
|
||||
|
||||
private static final Map<String, Function<SysAgriLimit, Integer>> LIMIT_MAP = new HashMap<>();
|
||||
private static final Set<String> VALID_FUNC_CODES = new HashSet<>();
|
||||
static {
|
||||
LIMIT_MAP.put("jm1g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1gLimit())));
|
||||
LIMIT_MAP.put("jm2g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2gLimit())));
|
||||
LIMIT_MAP.put("jbg1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbgLimit())));
|
||||
LIMIT_MAP.put("jm3g1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3gLimit())));
|
||||
LIMIT_MAP.put("jm2k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm2kLimit())));
|
||||
LIMIT_MAP.put("jm3k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm3kLimit())));
|
||||
LIMIT_MAP.put("jbk1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJbkLimit())));
|
||||
LIMIT_MAP.put("jm1k1", agriLimit -> Integer.parseInt(String.valueOf(agriLimit.getJm1kLimit())));
|
||||
}
|
||||
|
||||
|
||||
// ========== 常量定义(新增) ==========
|
||||
private static final int WORK_MODE_AUTO = 1; // 自动模式
|
||||
private static final int NOT_DELETED = 0; // 未删除
|
||||
private static final String LOCK_PREFIX = "lock:";
|
||||
private static final String AUTO_MODE = "auto_mode";
|
||||
private static final String CREATE_BY = "条件控制";
|
||||
private static final int OP_SOURCE = 3; // 操作来源:条件控制
|
||||
private static final int LOCK_ACQUIRED = 1; // 是否获取锁
|
||||
private static final int DEFAULT_RUN_TIME = 300; // 默认运行时间
|
||||
|
||||
public void checkAutoTerm() {
|
||||
try {
|
||||
log.info("=============【定时任务】大棚自动模式监测开始执行,时间:{}=============", LocalDateTime.now());
|
||||
// 查询自动模式的大棚
|
||||
List<SysAgriInfo> agriInfos = agriInfoService.lambdaQuery()
|
||||
.select(SysAgriInfo::getImei, SysAgriInfo::getAgriName)
|
||||
.eq(SysAgriInfo::getWorkMode, WORK_MODE_AUTO)
|
||||
.eq(SysAgriInfo::getIsDeleted, NOT_DELETED)
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(agriInfos)) return;
|
||||
// 取imei集合
|
||||
List<String> imeiList = agriInfos.stream().map(SysAgriInfo::getImei).collect(Collectors.toList());
|
||||
if (CollectionUtils.isEmpty(imeiList)) return;
|
||||
|
||||
// 根据imei 查询dtu_data最后一条温度数据
|
||||
List<Map<String, Object>> dtuDataList = dtuDataService.getLastDtuDataByImeiList(imeiList);
|
||||
if (CollectionUtils.isEmpty(dtuDataList)) return;
|
||||
// 根据温湿度imei分组
|
||||
Map<String, List<Map<String, Object>>> dtuDataByImeiMap
|
||||
= dtuDataList.stream().collect(Collectors.groupingBy(map -> (String) map.get("imei")));
|
||||
|
||||
// 获取所有开启自动化模式的大棚列表的卷膜参数和条件设置
|
||||
List<RollerTermVO> rollerTermList = rollerParamService.getRollerTerms(imeiList);
|
||||
if (CollectionUtils.isEmpty(rollerTermList)) {
|
||||
// todo 无参数设置和条件列表直接返回
|
||||
log.error("【定时任务-卷膜自动化控制】无参数设置和条件列表直接返回!");
|
||||
return;
|
||||
}
|
||||
// 按imei分组 → 再按roller分组(一步到位)
|
||||
Map<String, Map<String, List<RollerTermVO>>> rollerTermMap = rollerTermList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
RollerTermVO::getImei,
|
||||
Collectors.groupingBy(RollerTermVO::getRoller)
|
||||
));
|
||||
|
||||
// 查询每个IMEI今天的第一条日志
|
||||
Map<String, Map<String, Integer>> todayLogCountByImeiMap = devOperLogService.getTodayLogCountByImeiMap(imeiList);
|
||||
ArrayList<SysImeiAutoLog> logArrayList = new ArrayList<SysImeiAutoLog>();
|
||||
// 循环所有开启自动化的大棚
|
||||
for (SysAgriInfo agriInfo : agriInfos) {
|
||||
String imei = agriInfo.getImei();
|
||||
String agriName = agriInfo.getAgriName();
|
||||
// 获取温湿度指定imei的数据
|
||||
List<Map<String, Object>> dtuDataInfo = dtuDataByImeiMap.get(imei);
|
||||
// 该大棚温湿度不存在
|
||||
if (CollectionUtils.isEmpty(dtuDataInfo)) {
|
||||
// todo 该大棚下1分钟内无最新温湿度,怀疑离线
|
||||
log.error("【定时任务-卷膜自动化控制】大棚『{}』1分钟内无最新温湿度,怀疑离线", imei);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 最后一条对应imei对应温度 及时间
|
||||
Map<String, Object> dtuData = dtuDataInfo.get(0);
|
||||
// 求温度上报时间
|
||||
LocalDateTime dtuTime = (LocalDateTime) dtuData.get("time");
|
||||
if (dtuTime == null) {
|
||||
// todo 当前大棚温湿度时间为空 跳过
|
||||
log.error("【定时任务-卷膜自动化控制】大棚『{}』温湿度时间「{}」为空, 跳过", imei, LocalDateTime.now().minusMinutes(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取当前imei下的所有参数设置以及卷膜自动化条件设置
|
||||
Map<String, List<RollerTermVO>> configTermByRollerMap = rollerTermMap.get(imei);
|
||||
if (MapUtil.isEmpty(configTermByRollerMap)) {
|
||||
// todo 当前大棚下没有设置条件或者参数
|
||||
log.error("【定时任务-卷膜自动化控制】大棚『{}』当前大棚下没有设置条件或者参数, 跳过", imei);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 获取今天对应imei的日志
|
||||
Map<String, Integer> todayLogByRoller = todayLogCountByImeiMap.get(imei);
|
||||
|
||||
for (Map.Entry<String, List<RollerTermVO>> configEntry : configTermByRollerMap.entrySet()) {
|
||||
String roller = configEntry.getKey(); // 当前卷膜
|
||||
List<RollerTermVO> terms = configEntry.getValue(); // 当前卷膜条件
|
||||
// 每个卷膜分组只会有一个卷膜参数设置,所有取第一个即可
|
||||
if (terms == null || terms.isEmpty()) {
|
||||
// todo 当前卷膜 无参数设置,跳过当前roller
|
||||
log.error("【定时任务-卷膜自动化控制】大棚『{}』当前卷膜「{}」无参数设置,跳过当前roller", imei, roller);
|
||||
continue;
|
||||
}
|
||||
LocalDateTime startTime = terms.stream()
|
||||
.max(Comparator.comparing(RollerTermVO::getStartTime))
|
||||
.get()
|
||||
.getStartTime();
|
||||
// 获取卷膜参数
|
||||
RollerTermVO rollerConfig = terms.get(0);
|
||||
String refTempCode = rollerConfig.getRefTempCode(); // 参考温度
|
||||
BigDecimal ventTotalLen = rollerConfig.getVentTotalLen(); // 风口总长
|
||||
BigDecimal reservedLen = rollerConfig.getReservedLen(); // 预留风口
|
||||
|
||||
// 防御性判断:避免dtuData.get(refTempCode)为null
|
||||
Object tempObj = dtuData.get(refTempCode);
|
||||
if (tempObj == null) {
|
||||
// todo 当前卷膜参考温度设置为空
|
||||
log.error("【定时任务-卷膜自动化控制】大棚『{}』当前卷膜「{}」参考温度设置为空,跳过!", imei, roller);
|
||||
continue;
|
||||
}
|
||||
// 优化:明确标注为当前roller的参考温度快照(仅解析一次)
|
||||
BigDecimal currentTemp = new BigDecimal(tempObj.toString());
|
||||
|
||||
// 遍历当前roller的所有term(改用普通for循环,可读性更高)
|
||||
for (RollerTermVO term : terms) {
|
||||
// 判断该温度上报时间是否在该条件设置的时间范围内
|
||||
boolean inRange = TimeRangeUtil.isTimeInRange(dtuTime, term.getStartTime(), term.getEndTime());
|
||||
boolean isCancelOff = startTime.equals(term.getStartTime());
|
||||
log.info("\n【定时任务-卷膜自动化控制】正在监测大棚『{}』-卷膜『{}』:" +
|
||||
"条件设置详情,监控时间范围:『{}~{}』,适宜温度:{}℃,运行风口:{}cm。「{}」",
|
||||
imei,roller,term.getStartTime().format(FORMATTER),term.getEndTime().format(FORMATTER),
|
||||
term.getTemp(),term.getVent(), isCancelOff?"当前为卷膜「"+roller+"」最后一条自动化规则":"");
|
||||
if (!inRange) {
|
||||
log.info("【定时任务-卷膜自动化控制】大棚『{}』当前卷膜「{}」温湿度时间:「{}」不在监控时间范围内「{}~{}」,跳过!",
|
||||
imei, roller, dtuTime,term.getStartTime().format(FORMATTER),term.getEndTime().format(FORMATTER));
|
||||
continue;
|
||||
}
|
||||
// 在范围内
|
||||
//判断温度是否在适宜温度内
|
||||
TempCommandStatus tempCommandStatus = TempJudgeUtil.judgeTempCommand(currentTemp, term.getTemp());
|
||||
SysImeiAutoLog imeiAutoLog = new SysImeiAutoLog();
|
||||
imeiAutoLog.setImei(imei);
|
||||
imeiAutoLog.setMonitorPeriod(term.getStartTime().format(FORMATTER)+"~"+term.getEndTime().format(FORMATTER));
|
||||
imeiAutoLog.setCurrentTemp(currentTemp);
|
||||
imeiAutoLog.setRefTemp(refTempCode);
|
||||
imeiAutoLog.setSuitableTemp(term.getTemp());
|
||||
imeiAutoLog.setFanStatus(term.getVent());
|
||||
imeiAutoLog.setIsLast(isCancelOff?1:0);
|
||||
// todo 开关指令需要通知用户 推送主题 && 更新数据 前端重新请求消息表
|
||||
if (tempCommandStatus == TempCommandStatus.OPEN) {
|
||||
log.info("【定时任务-卷膜自动化控制】大棚『{}』-卷膜『{}』当前温湿度:『{}℃』,适宜温度为:「{}℃」,触发自动化条件,即将执行『开』指令!",
|
||||
imei, roller, currentTemp, term.getTemp());
|
||||
// 判断是否首次开
|
||||
Integer openLen = todayLogByRoller.getOrDefault(roller + "k1", 0);
|
||||
imeiAutoLog.setRollFilm(roller);
|
||||
imeiAutoLog.setExecCmd("开");
|
||||
// 开指令
|
||||
sendOpenCommand(imei, agriName, roller, openLen == 0, term.getVent(), reservedLen);
|
||||
// 每次后,数量累计+1 不需要因为只循环到一次
|
||||
} else if (tempCommandStatus == TempCommandStatus.CLOSE) {
|
||||
log.info("【定时任务-卷膜自动化控制】大棚『{}』-卷膜『{}』当前温湿度:『{}℃』,适宜温度为:「{}℃」,触发自动化条件,即将执行『关』指令!",
|
||||
imei, roller, currentTemp, term.getTemp());
|
||||
// 判断是否首次开
|
||||
Integer closeLen = todayLogByRoller.getOrDefault(roller + "g1", 0);
|
||||
imeiAutoLog.setRollFilm(roller);
|
||||
imeiAutoLog.setExecCmd("关");
|
||||
// 关指令
|
||||
sendCloseCommand(imei, agriName, roller, closeLen == 0, term.getVent(), isCancelOff);
|
||||
// 每次后,数量累计+1
|
||||
} else {
|
||||
log.info("【定时任务-卷膜自动化控制】大棚『{}』-卷膜『{}』当前温湿度:『{}℃』,适宜温度为:「{}℃」,温度适宜,无需操作!",
|
||||
imei, roller, currentTemp, term.getTemp());
|
||||
}
|
||||
logArrayList.add(imeiAutoLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
imeiAutoLogService.saveBatch(logArrayList);
|
||||
log.info("=============【定时任务】大棚自动模式监测执行完毕,时间:{}=============", LocalDateTime.now());
|
||||
} catch (Exception e) {
|
||||
WxUtil.pushText("【定时任务】大棚自动模式监测执行终端, \n发生错误.错误原因:"+e+",\n时间:"+LocalDateTime.now());
|
||||
log.error("\n=============【定时任务】大棚自动模式监测执行终端,\n发生错误.错误原因:{},\n时间:{}=============", e, LocalDateTime.now());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 发送开指令
|
||||
* @param imei 设备唯一标识
|
||||
* @param agriName 大棚名称
|
||||
* @param roller 卷膜标识
|
||||
* @param isFirstRun 是否第一次执行
|
||||
* @param vent 每次执行的风口大小
|
||||
* @param reservedLen 预留风口长度
|
||||
*/
|
||||
private void sendOpenCommand(String imei, String agriName, String roller, boolean isFirstRun,
|
||||
BigDecimal vent, BigDecimal reservedLen) {
|
||||
// ========== 1. 前置参数校验(防御性判断) ==========
|
||||
validateBaseParams(imei, agriName, roller);
|
||||
if (vent == null) {
|
||||
log.error("【开指令】设备{}卷膜{}风口大小为空,指令发送失败", imei, roller);
|
||||
return;
|
||||
}
|
||||
if (isFirstRun && reservedLen == null) {
|
||||
log.error("【开指令】设备{}卷膜{}首次执行但预留风口为空,指令发送失败", imei, roller);
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== 2. 计算开指令风口长度 ==========
|
||||
BigDecimal openLen = vent;
|
||||
if (isFirstRun) {
|
||||
log.error("【自动模式】设备【{}】卷膜【{}】今日首次执行开指令,叠加预留风口{}", imei, roller, reservedLen);
|
||||
openLen = openLen.add(reservedLen);
|
||||
}
|
||||
String funcType = roller + "k1";
|
||||
String message = buildMqttMessage(funcType);
|
||||
|
||||
// ========== 3. 执行核心指令逻辑 ==========
|
||||
executeCommand(imei, agriName, roller, funcType, message, openLen, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送关指令
|
||||
* @param imei 设备唯一标识
|
||||
* @param agriName 大棚名称
|
||||
* @param roller 卷膜标识
|
||||
* @param isFirstRun 是否第一次执行
|
||||
* @param vent 每次执行的风口大小
|
||||
*/
|
||||
private void sendCloseCommand(String imei, String agriName, String roller,
|
||||
boolean isFirstRun, BigDecimal vent, boolean isCancelOff) {
|
||||
// ========== 1. 前置参数校验 ==========
|
||||
validateBaseParams(imei, agriName, roller);
|
||||
if (isFirstRun) {
|
||||
log.error("【关指令】设备{}卷膜{}今日首次执行,直接返回不发送关指令", imei, roller);
|
||||
return;
|
||||
}
|
||||
if (vent == null) {
|
||||
log.error("【关指令】设备{}卷膜{}风口大小为空,指令发送失败", imei, roller);
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== 2. 构建关指令参数 ==========
|
||||
String funcType = roller + "g1";
|
||||
String message = buildMqttMessage(funcType);
|
||||
|
||||
// ========== 3. 执行核心指令逻辑 ==========
|
||||
executeCommand(imei, agriName, roller, funcType, message, vent, false, isCancelOff);
|
||||
}
|
||||
|
||||
// ========== 抽取公共方法:减少代码冗余 ==========
|
||||
|
||||
/**
|
||||
* 基础参数校验
|
||||
* @param imei 设备ID
|
||||
* @param agriName 大棚名称
|
||||
* @param roller 卷膜标识
|
||||
*/
|
||||
private void validateBaseParams(String imei, String agriName, String roller) {
|
||||
if (StringUtils.isBlank(imei)) {
|
||||
throw new IllegalArgumentException("设备IMEI不能为空");
|
||||
}
|
||||
if (StringUtils.isBlank(agriName)) {
|
||||
log.warn("【指令】设备{}卷膜{}大棚名称为空,仍继续执行指令", imei, roller);
|
||||
}
|
||||
if (StringUtils.isBlank(roller)) {
|
||||
throw new IllegalArgumentException("卷膜标识不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建MQTT指令消息
|
||||
* @param funcType 功能类型(如roller1k1/roller1g1)
|
||||
* @return 格式化的MQTT消息字符串
|
||||
*/
|
||||
private String buildMqttMessage(String funcType) {
|
||||
return String.format("{\"%s\":1}", funcType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行指令核心逻辑(分布式锁+日志记录+MQTT发布+自动关调度)
|
||||
* @param imei 设备ID
|
||||
* @param agriName 大棚名称
|
||||
* @param roller 卷膜标识
|
||||
* @param funcType 功能类型
|
||||
* @param message MQTT消息
|
||||
* @param len 风口长度(用于计算运行时间)
|
||||
* @param isOpen 是否开指令
|
||||
*/
|
||||
private void executeCommand(String imei, String agriName, String roller, String funcType,
|
||||
String message, BigDecimal len, boolean isOpen, boolean isCancelOff) {
|
||||
String lockKey = LOCK_PREFIX + imei + ":" + funcType;
|
||||
try {
|
||||
// ========== 1. 获取分布式锁 ==========
|
||||
Boolean lockSuccess = stringRedisTemplate.opsForValue().setIfAbsent(
|
||||
lockKey, AUTO_MODE, dtuCtlLockTTL, TimeUnit.SECONDS
|
||||
);
|
||||
if (lockSuccess == null || !lockSuccess) {
|
||||
log.warn("【分布式锁】自动模式下{}设备{}的{}功能失败,可能存在并发操作",
|
||||
isOpen ? "开启" : "关闭", imei, funcType);
|
||||
return;
|
||||
}
|
||||
|
||||
// ========== 2. 记录操作日志 ==========
|
||||
log.debug("【指令处理】自动模式下触发{}设备{}的{}功能,指令:{}",
|
||||
isOpen ? "开启" : "关闭", imei, funcType, message);
|
||||
|
||||
// ========== 3. 发布MQTT指令 ==========todo
|
||||
mqttMessageSender.publish("dtu/" + imei + "/down", message);
|
||||
|
||||
// ========== 4. 计算运行时间并调度自动关 ==========
|
||||
int runTime = RollerTimeCalculator.calculateRunTime(len);
|
||||
if (isCancelOff) {
|
||||
// 如果最后一条则遵循手动限位设置,如果没设置默认300秒
|
||||
SysAgriLimit agriLimit = agriLimitService.lambdaQuery()
|
||||
.eq(SysAgriLimit::getImei, imei)
|
||||
.one();
|
||||
if (agriLimit != null) {
|
||||
runTime = LIMIT_MAP.getOrDefault(funcType, k -> DEFAULT_RUN_TIME).apply(agriLimit);
|
||||
}
|
||||
log.debug("【自动关调度】设备{}卷膜{}:触发最后一条自动化条件,遵循手动限位设置!时间:{}", imei, roller, LocalDateTime.now());
|
||||
}
|
||||
if (runTime > 0) {
|
||||
String autoOffKey = roller + (isOpen ? "k1" : "g1");
|
||||
autoOffManager.scheduleAutoOff(imei, autoOffKey, runTime);
|
||||
log.debug("【自动关调度】设备{}卷膜「{}:{}」调度{}秒后自动关闭", imei, roller,(isOpen?"开":"关"), runTime);
|
||||
}
|
||||
saveOperLog(imei, agriName, funcType, message, isOpen ? 1 : 0, isCancelOff, runTime);
|
||||
}
|
||||
// catch (MqttException e) {
|
||||
// // ========== 异常处理:记录详细日志,不抛运行时异常 ==========
|
||||
// log.error("【MQTT异常】{}设备{}的{}功能指令发布失败,指令:{}",
|
||||
// isOpen ? "开启" : "关闭", imei, funcType, message, e);
|
||||
// }
|
||||
|
||||
catch (Exception e) {
|
||||
// 兜底异常捕获:避免未知异常导致锁无法释放(依赖TTL兜底)
|
||||
log.error("【指令执行异常】{}设备{}的{}功能执行失败",
|
||||
isOpen ? "开启" : "关闭", imei, funcType, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存设备操作日志
|
||||
* @param imei 设备ID
|
||||
* @param agriName 大棚名称
|
||||
* @param funcCode 功能码
|
||||
* @param payload 指令内容
|
||||
* @param opType 操作类型(1-开,0-关)
|
||||
*/
|
||||
private void saveOperLog(String imei, String agriName,
|
||||
String funcCode, String payload, int opType, boolean isCancelOff, int runTime) {
|
||||
SysDevOperLog logDto = new SysDevOperLog();
|
||||
logDto.setAgriName(agriName);
|
||||
logDto.setImei(imei);
|
||||
logDto.setFuncCode(funcCode);
|
||||
logDto.setOpType(opType);
|
||||
logDto.setOpSource(OP_SOURCE);
|
||||
logDto.setPayload(payload);
|
||||
logDto.setRunTime(runTime);
|
||||
logDto.setLockAcquired(LOCK_ACQUIRED); // 已获取锁
|
||||
logDto.setLockHolder(AUTO_MODE);
|
||||
logDto.setIsTask(isCancelOff?0:1);
|
||||
if (isCancelOff) {
|
||||
logDto.setNoTaskReason("触发最后一条自动化指令,遵循手动限位设置,默认300秒");
|
||||
}
|
||||
logDto.setCreateBy(CREATE_BY);
|
||||
// 可选:增加异常捕获,避免日志保存失败影响指令执行
|
||||
try {
|
||||
devOperLogService.save(logDto);
|
||||
log.info("【日志保存】设备{}功能{}日志保存成功,日志id:{}", imei, funcCode,logDto.getId());
|
||||
} catch (Exception e) {
|
||||
log.error("【日志保存失败】设备{}功能{}日志保存失败", imei, funcCode, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
package com.agri.quartz.task;
|
||||
|
||||
import com.agri.system.domain.SysDtuData;
|
||||
import com.agri.system.service.ISysDtuDataService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Component("tempTask")
|
||||
public class TempTask {
|
||||
|
||||
@Autowired
|
||||
private ISysDtuDataService dtuDataService;
|
||||
|
||||
public void ryNoParams()
|
||||
{
|
||||
dtuDataService.lambdaUpdate()
|
||||
.eq(SysDtuData::getImei, "864865085008523")
|
||||
.orderByDesc(SysDtuData::getId)
|
||||
.last("limit 1")
|
||||
.set(SysDtuData::getTime, new Date())
|
||||
.set(SysDtuData::getCreateTime, new Date())
|
||||
.update();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,21 +5,22 @@ import com.agri.common.core.controller.BaseController;
|
|||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.common.utils.SecurityUtils;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysUserAgri;
|
||||
import com.agri.system.domain.vo.AgriInfoView;
|
||||
import com.agri.system.service.ISysAgriInfoService;
|
||||
import com.agri.system.service.ISysUserAgriService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 大棚管理Controller
|
||||
|
|
@ -34,8 +35,6 @@ public class SysAgriInfoController extends BaseController
|
|||
@Autowired
|
||||
private ISysAgriInfoService sysAgriInfoService;
|
||||
|
||||
@Autowired
|
||||
private ISysUserAgriService userAgriService;
|
||||
/**
|
||||
* 查询大棚管理列表
|
||||
*/
|
||||
|
|
@ -44,16 +43,10 @@ public class SysAgriInfoController extends BaseController
|
|||
public TableDataInfo list(SysAgriInfo sysAgriInfo)
|
||||
{
|
||||
startPage();
|
||||
List<SysAgriInfo> list = sysAgriInfoService.findAgriByUser(sysAgriInfo);
|
||||
List<SysAgriInfo> list = sysAgriInfoService.selectSysAgriInfoList(sysAgriInfo);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('assets:agri:list')")
|
||||
@GetMapping("/findAgriByUser")
|
||||
public AjaxResult findAgriByUser(SysAgriInfo sysAgriInfo) {
|
||||
List<SysAgriInfo> list = sysAgriInfoService.findAgriByUser(sysAgriInfo);
|
||||
return success(list);
|
||||
}
|
||||
/**
|
||||
* 导出大棚管理列表
|
||||
*/
|
||||
|
|
@ -109,74 +102,4 @@ public class SysAgriInfoController extends BaseController
|
|||
{
|
||||
return toAjax(sysAgriInfoService.deleteSysAgriInfoByIds(ids));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('assets:agri:list')")
|
||||
@GetMapping("/findAgriInfoByUser")
|
||||
public AjaxResult findAgriInfoByUser(SysAgriInfo sysAgriInfo) {
|
||||
List<AgriInfoView> list = sysAgriInfoService.findAgriInfoByUser(sysAgriInfo);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过移动端添加大棚信息,默认添加当前用户为所有者
|
||||
* @param sysAgriInfo
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:agri:addAgriFromMobile')")
|
||||
@PostMapping("/addAgriFromMobile")
|
||||
public AjaxResult addAgriFromMobile(@RequestBody SysAgriInfo sysAgriInfo) {
|
||||
|
||||
return success(sysAgriInfoService.addAgriFromMobile(sysAgriInfo));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('assets:agri:switchAgriMode')")
|
||||
@PostMapping("/switchAgriMode/{imei}")
|
||||
public AjaxResult switchAgriMode(@PathVariable String imei, @RequestParam("code") Integer code) {
|
||||
|
||||
if (StringUtils.isEmpty(imei) || code == null) {
|
||||
return error();
|
||||
}
|
||||
sysAgriInfoService.lambdaUpdate()
|
||||
.eq(SysAgriInfo::getImei, imei)
|
||||
.set(SysAgriInfo::getWorkMode, code)
|
||||
.update();
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改大棚名称
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:agri:edit')")
|
||||
@Log(title = "大棚管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/renameAgriName")
|
||||
public AjaxResult renameAgriName(@RequestParam("agriId") String agriId,
|
||||
@RequestParam("imei") String imei,
|
||||
@RequestParam("newAgriName") String newAgriName)
|
||||
{
|
||||
boolean update = false;
|
||||
if (SecurityUtils.isAdmin()) {
|
||||
update = sysAgriInfoService.lambdaUpdate()
|
||||
.eq(SysAgriInfo::getImei, imei)
|
||||
.set(SysAgriInfo::getAgriName, newAgriName)
|
||||
.update();
|
||||
} else {
|
||||
update = userAgriService.lambdaUpdate()
|
||||
.eq(SysUserAgri::getUserId, SecurityUtils.getUserId())
|
||||
.eq(SysUserAgri::getAgriId, imei)
|
||||
.set(SysUserAgri::getAgriName, newAgriName)
|
||||
.update();
|
||||
}
|
||||
|
||||
return update? success():error();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备分享信息(可分享列表 + 分享给我的设备列表)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:agri:list')")
|
||||
@GetMapping("/selectShareInfo")
|
||||
public AjaxResult selectShareInfo(SysAgriInfo agriInfo) {
|
||||
Map<String, Object> result = sysAgriInfoService.selectShareInfoByUser(agriInfo);
|
||||
return success(result);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,124 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.agri.system.domain.SysAgriLimit;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysAgriLimitBak;
|
||||
import com.agri.system.service.ISysAgriLimitBakService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 大棚功能执行时间限位Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/assets/limit_bak")
|
||||
public class SysAgriLimitBakController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysAgriLimitBakService sysAgriLimitBakService;
|
||||
|
||||
/**
|
||||
* 查询大棚功能执行时间限位列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysAgriLimitBak sysAgriLimitBak)
|
||||
{
|
||||
startPage();
|
||||
List<SysAgriLimitBak> list = sysAgriLimitBakService.selectSysAgriLimitBakList(sysAgriLimitBak);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出大棚功能执行时间限位列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:export')")
|
||||
@Log(title = "大棚功能执行时间限位", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysAgriLimitBak sysAgriLimitBak)
|
||||
{
|
||||
List<SysAgriLimitBak> list = sysAgriLimitBakService.selectSysAgriLimitBakList(sysAgriLimitBak);
|
||||
ExcelUtil<SysAgriLimitBak> util = new ExcelUtil<SysAgriLimitBak>(SysAgriLimitBak.class);
|
||||
util.exportExcel(response, list, "大棚功能执行时间限位数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大棚功能执行时间限位详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(sysAgriLimitBakService.selectSysAgriLimitBakById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增大棚功能执行时间限位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:add')")
|
||||
@Log(title = "大棚功能执行时间限位", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysAgriLimitBak sysAgriLimitBak)
|
||||
{
|
||||
return toAjax(sysAgriLimitBakService.insertSysAgriLimitBak(sysAgriLimitBak));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改大棚功能执行时间限位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:edit')")
|
||||
@Log(title = "大棚功能执行时间限位", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysAgriLimitBak sysAgriLimitBak)
|
||||
{
|
||||
return toAjax(sysAgriLimitBakService.updateSysAgriLimitBak(sysAgriLimitBak));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除大棚功能执行时间限位
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:remove')")
|
||||
@Log(title = "大棚功能执行时间限位", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(sysAgriLimitBakService.deleteSysAgriLimitBakByIds(ids));
|
||||
}
|
||||
|
||||
|
||||
@Log(title = "大棚运行时间限位查询", businessType = BusinessType.SELECT)
|
||||
@GetMapping("/getAgriLimitByImei/{imei}")
|
||||
public AjaxResult getAgriLimitByImei(@PathVariable String imei)
|
||||
{
|
||||
SysAgriLimitBak agriLimit = sysAgriLimitBakService.getAgriLimitByImei(imei);
|
||||
return success(agriLimit);
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('assets:limit_bak:add')")
|
||||
@Log(title = "大棚功能执行时间限位", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/saveAgriLimit")
|
||||
public AjaxResult saveAgriLimit(@RequestBody SysAgriLimitBak sysAgriLimitBak)
|
||||
{
|
||||
return toAjax(sysAgriLimitBakService.saveAgriLimit(sysAgriLimitBak));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.agri.common.utils.StringUtils;
|
||||
import com.agri.system.domain.vo.AgriTermVo;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysAutoTerm;
|
||||
import com.agri.system.service.ISysAutoTermService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 卷膜运行条件Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/control/autoTerm")
|
||||
public class SysAutoTermController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysAutoTermService sysAutoTermService;
|
||||
|
||||
/**
|
||||
* 查询卷膜运行条件列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysAutoTerm sysAutoTerm)
|
||||
{
|
||||
startPage();
|
||||
List<SysAutoTerm> list = sysAutoTermService.selectSysAutoTermList(sysAutoTerm);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出卷膜运行条件列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:export')")
|
||||
@Log(title = "卷膜运行条件", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysAutoTerm sysAutoTerm)
|
||||
{
|
||||
List<SysAutoTerm> list = sysAutoTermService.selectSysAutoTermList(sysAutoTerm);
|
||||
ExcelUtil<SysAutoTerm> util = new ExcelUtil<SysAutoTerm>(SysAutoTerm.class);
|
||||
util.exportExcel(response, list, "卷膜运行条件数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卷膜运行条件详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(sysAutoTermService.selectSysAutoTermById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增卷膜运行条件
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:add')")
|
||||
@Log(title = "卷膜运行条件", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysAutoTerm sysAutoTerm)
|
||||
{
|
||||
return toAjax(sysAutoTermService.insertSysAutoTerm(sysAutoTerm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改卷膜运行条件
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:edit')")
|
||||
@Log(title = "卷膜运行条件", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysAutoTerm sysAutoTerm)
|
||||
{
|
||||
return toAjax(sysAutoTermService.updateSysAutoTerm(sysAutoTerm));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除卷膜运行条件
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:remove')")
|
||||
@Log(title = "卷膜运行条件", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(sysAutoTermService.deleteSysAutoTermByIds(ids));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:saveAgriTerm')")
|
||||
@Log(title = "保存自动化条件", businessType = BusinessType.INSERT)
|
||||
@PutMapping("/saveAgriTerm")
|
||||
public AjaxResult saveAgriTerm(@RequestBody List<AgriTermVo> agriTerms) {
|
||||
if (CollectionUtils.isEmpty(agriTerms)) {
|
||||
return error("保存失败!自动化条件设置为空!");
|
||||
} else {
|
||||
String validateTips = sysAutoTermService.validate(agriTerms);
|
||||
if (StringUtils.isNotEmpty(validateTips)) {
|
||||
return error(validateTips);
|
||||
}
|
||||
}
|
||||
sysAutoTermService.saveAgriTerm(agriTerms);
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前设备下所有条件
|
||||
* @param imei
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:autoTerm:query')")
|
||||
@GetMapping("/getAgriTerm/{imei}")
|
||||
public AjaxResult getAgriTerm(@PathVariable String imei) {
|
||||
|
||||
return success(sysAutoTermService.getAgriTerm(imei));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
import com.agri.system.service.ISysDevOperLogService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 设备控制操作日志Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/control/controllog")
|
||||
public class SysDevOperLogController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDevOperLogService sysDevOperLogService;
|
||||
|
||||
/**
|
||||
* 查询设备控制操作日志列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:controllog:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysDevOperLog sysDevOperLog)
|
||||
{
|
||||
startPage();
|
||||
List<SysDevOperLog> list = sysDevOperLogService.selectSysDevOperLogList(sysDevOperLog);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出设备控制操作日志列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:controllog:export')")
|
||||
@Log(title = "设备控制操作日志", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysDevOperLog sysDevOperLog)
|
||||
{
|
||||
List<SysDevOperLog> list = sysDevOperLogService.selectSysDevOperLogList(sysDevOperLog);
|
||||
ExcelUtil<SysDevOperLog> util = new ExcelUtil<SysDevOperLog>(SysDevOperLog.class);
|
||||
util.exportExcel(response, list, "设备控制操作日志数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备控制操作日志详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:controllog:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(sysDevOperLogService.selectSysDevOperLogById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增设备控制操作日志
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:controllog:add')")
|
||||
@Log(title = "设备控制操作日志", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysDevOperLog sysDevOperLog)
|
||||
{
|
||||
return toAjax(sysDevOperLogService.insertSysDevOperLog(sysDevOperLog));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改设备控制操作日志
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:controllog:edit')")
|
||||
@Log(title = "设备控制操作日志", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysDevOperLog sysDevOperLog)
|
||||
{
|
||||
return toAjax(sysDevOperLogService.updateSysDevOperLog(sysDevOperLog));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除设备控制操作日志
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:controllog:remove')")
|
||||
@Log(title = "设备控制操作日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids)
|
||||
{
|
||||
return toAjax(sysDevOperLogService.deleteSysDevOperLogByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +1,17 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
|
|
@ -108,14 +112,4 @@ public class SysDtuDataController extends BaseController
|
|||
{
|
||||
return toAjax(sysDtuDataService.deleteSysDtuDataByIds(ids));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('system:data:query')")
|
||||
@GetMapping(value = "/getHistoryData")
|
||||
public AjaxResult getHistoryData(@RequestParam("imei") String imei,
|
||||
@RequestParam(value = "startTime",required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
|
||||
@RequestParam(value = "endTime",required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime)
|
||||
{
|
||||
return success(sysDtuDataService.getHistoryData(imei,startTime,endTime));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,120 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.agri.system.domain.SysDtuRemark;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysDtuRemarkBak;
|
||||
import com.agri.system.service.ISysDtuRemarkBakService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* dtu设备备注Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/assets/remark_bak")
|
||||
public class SysDtuRemarkBakController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysDtuRemarkBakService sysDtuRemarkBakService;
|
||||
|
||||
/**
|
||||
* 查询dtu设备备注列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysDtuRemarkBak sysDtuRemarkBak)
|
||||
{
|
||||
startPage();
|
||||
List<SysDtuRemarkBak> list = sysDtuRemarkBakService.selectSysDtuRemarkBakList(sysDtuRemarkBak);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出dtu设备备注列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:export')")
|
||||
@Log(title = "dtu设备备注", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysDtuRemarkBak sysDtuRemarkBak)
|
||||
{
|
||||
List<SysDtuRemarkBak> list = sysDtuRemarkBakService.selectSysDtuRemarkBakList(sysDtuRemarkBak);
|
||||
ExcelUtil<SysDtuRemarkBak> util = new ExcelUtil<SysDtuRemarkBak>(SysDtuRemarkBak.class);
|
||||
util.exportExcel(response, list, "dtu设备备注数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取dtu设备备注详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(sysDtuRemarkBakService.selectSysDtuRemarkBakById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增dtu设备备注
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:add')")
|
||||
@Log(title = "dtu设备备注", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysDtuRemarkBak sysDtuRemarkBak)
|
||||
{
|
||||
return toAjax(sysDtuRemarkBakService.insertSysDtuRemarkBak(sysDtuRemarkBak));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改dtu设备备注
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:edit')")
|
||||
@Log(title = "dtu设备备注", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysDtuRemarkBak sysDtuRemarkBak)
|
||||
{
|
||||
return toAjax(sysDtuRemarkBakService.updateSysDtuRemarkBak(sysDtuRemarkBak));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除dtu设备备注
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:remove')")
|
||||
@Log(title = "dtu设备备注", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(sysDtuRemarkBakService.deleteSysDtuRemarkBakByIds(ids));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取dtu设备备注详细信息getDtuRemarkByImei
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:list')")
|
||||
@GetMapping(value = "/getDtuRemarkByImei")
|
||||
public AjaxResult getDtuRemarkByImei(@RequestParam("imei") String imei)
|
||||
{
|
||||
SysDtuRemarkBak dtuRemark = sysDtuRemarkBakService.getDtuRemarkByImei(imei);
|
||||
return success(dtuRemark);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark_bak:add')")
|
||||
@Log(title = "dtu设备备注", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/saveAgriRemark")
|
||||
public AjaxResult saveAgriRemark(@RequestBody SysDtuRemarkBak sysDtuRemarkBak)
|
||||
{
|
||||
return toAjax(sysDtuRemarkBakService.saveAgriRemark(sysDtuRemarkBak));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +1,24 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.ibatis.ognl.ObjectElementsAccessor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.system.domain.SysDtuRemark;
|
||||
import com.agri.system.service.ISysDtuRemarkService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* dtu设备备注Controller
|
||||
*
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-21
|
||||
*/
|
||||
|
|
@ -56,7 +57,7 @@ public class SysDtuRemarkController extends BaseController
|
|||
/**
|
||||
* 获取dtu设备备注详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark:list')")
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
|
|
@ -100,7 +101,7 @@ public class SysDtuRemarkController extends BaseController
|
|||
/**
|
||||
* 获取dtu设备备注详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark:list')")
|
||||
@PreAuthorize("@ss.hasPermi('assets:remark:query')")
|
||||
@GetMapping(value = "/getDtuByImei")
|
||||
public AjaxResult getDtuByImei(@RequestParam("imei") String imei)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysImeiAutoLog;
|
||||
import com.agri.system.service.ISysImeiAutoLogService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 自动模式日志Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-29
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/warn/autolog")
|
||||
public class SysImeiAutoLogController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysImeiAutoLogService sysImeiAutoLogService;
|
||||
|
||||
/**
|
||||
* 查询自动模式日志列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysImeiAutoLog sysImeiAutoLog)
|
||||
{
|
||||
startPage();
|
||||
List<SysImeiAutoLog> list = sysImeiAutoLogService.selectSysImeiAutoLogList(sysImeiAutoLog);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出自动模式日志列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:export')")
|
||||
@Log(title = "自动模式日志", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysImeiAutoLog sysImeiAutoLog)
|
||||
{
|
||||
List<SysImeiAutoLog> list = sysImeiAutoLogService.selectSysImeiAutoLogList(sysImeiAutoLog);
|
||||
ExcelUtil<SysImeiAutoLog> util = new ExcelUtil<SysImeiAutoLog>(SysImeiAutoLog.class);
|
||||
util.exportExcel(response, list, "自动模式日志数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自动模式日志详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(sysImeiAutoLogService.selectSysImeiAutoLogById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增自动模式日志
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:add')")
|
||||
@Log(title = "自动模式日志", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysImeiAutoLog sysImeiAutoLog)
|
||||
{
|
||||
return toAjax(sysImeiAutoLogService.insertSysImeiAutoLog(sysImeiAutoLog));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改自动模式日志
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:edit')")
|
||||
@Log(title = "自动模式日志", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysImeiAutoLog sysImeiAutoLog)
|
||||
{
|
||||
return toAjax(sysImeiAutoLogService.updateSysImeiAutoLog(sysImeiAutoLog));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除自动模式日志
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:remove')")
|
||||
@Log(title = "自动模式日志", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids)
|
||||
{
|
||||
return toAjax(sysImeiAutoLogService.deleteSysImeiAutoLogByIds(ids));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询自动模式日志列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:autolog:list')")
|
||||
@GetMapping("/getAutoLogList")
|
||||
public AjaxResult getAutoLogList(SysImeiAutoLog sysImeiAutoLog)
|
||||
{
|
||||
List<SysImeiAutoLog> list = sysImeiAutoLogService.selectSysImeiAutoLogList(sysImeiAutoLog);
|
||||
return success(list);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.agri.common.utils.DateUtils;
|
||||
import com.agri.common.utils.SecurityUtils;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
import com.agri.system.service.ISysMessageService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 系统消息中心Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-26
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/warn/message")
|
||||
public class SysMessageController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysMessageService sysMessageService;
|
||||
|
||||
/**
|
||||
* 查询系统消息中心列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysMessage sysMessage)
|
||||
{
|
||||
startPage();
|
||||
List<SysMessage> list = sysMessageService.selectSysMessageList(sysMessage);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:list')")
|
||||
@GetMapping("/getMessage")
|
||||
public AjaxResult getMessage(SysMessage sysMessage)
|
||||
{
|
||||
List<SysMessage> list = sysMessageService.selectSysMessageList(sysMessage);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出系统消息中心列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:export')")
|
||||
@Log(title = "系统消息中心", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysMessage sysMessage)
|
||||
{
|
||||
List<SysMessage> list = sysMessageService.selectSysMessageList(sysMessage);
|
||||
ExcelUtil<SysMessage> util = new ExcelUtil<SysMessage>(SysMessage.class);
|
||||
util.exportExcel(response, list, "系统消息中心数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统消息中心详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(sysMessageService.selectSysMessageById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增系统消息中心
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:add')")
|
||||
@Log(title = "系统消息中心", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysMessage sysMessage)
|
||||
{
|
||||
return toAjax(sysMessageService.insertSysMessage(sysMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改系统消息中心
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:edit')")
|
||||
@Log(title = "系统消息中心", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysMessage sysMessage)
|
||||
{
|
||||
return toAjax(sysMessageService.updateSysMessage(sysMessage));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除系统消息中心
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:remove')")
|
||||
@Log(title = "系统消息中心", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids)
|
||||
{
|
||||
return toAjax(sysMessageService.deleteSysMessageByIds(ids));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询系统消息中心列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:list')")
|
||||
@GetMapping("/getNewMessage")
|
||||
public AjaxResult getNewMessage(SysMessage sysMessage)
|
||||
{
|
||||
List<SysMessage> list = sysMessageService.selectSysMessageList(sysMessage);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:edit')")
|
||||
@Log(title = "系统消息中心", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updateRead")
|
||||
public AjaxResult updateRead(@RequestBody SysMessage sysMessage)
|
||||
{
|
||||
if (SecurityUtils.isAdmin()) return success();
|
||||
sysMessageService.lambdaUpdate()
|
||||
.eq(SysMessage::getReceiver, SecurityUtils.getUserId())
|
||||
.eq(SysMessage::getReadStatus, 0)
|
||||
.eq(sysMessage.getId()!=null, SysMessage::getId, sysMessage.getId())
|
||||
.eq(StringUtils.isNotBlank(sysMessage.getMsgType()),
|
||||
SysMessage::getMsgType, sysMessage.getMsgType())
|
||||
.set(SysMessage::getReadStatus, 1)
|
||||
.update();
|
||||
return success();
|
||||
}
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:remove')")
|
||||
@Log(title = "排量删除历史记录", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/removeBatch")
|
||||
public AjaxResult removeBatch(@RequestBody SysMessage sysMessage)
|
||||
{
|
||||
QueryWrapper<SysMessage> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("receiver", SecurityUtils.getUserId());
|
||||
wrapper.eq("msg_type", sysMessage.getMsgType());
|
||||
sysMessageService.remove(wrapper);
|
||||
return success();
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:list')")
|
||||
@GetMapping("/getMsgOverview")
|
||||
public AjaxResult getMsgOverview(SysMessage sysMessage)
|
||||
{
|
||||
List<SysMessage> list = sysMessageService.getMsgOverview(sysMessage);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('warn:message:list')")
|
||||
@GetMapping("/unReadCount")
|
||||
public AjaxResult unReadCount()
|
||||
{
|
||||
|
||||
LocalDate localDate = LocalDate.now().minusDays(7);
|
||||
LocalDate localDate1 = LocalDate.now().plusDays(1);
|
||||
Long count = sysMessageService.lambdaQuery()
|
||||
.eq(SysMessage::getReceiver, SecurityUtils.getUserId())
|
||||
.eq(SysMessage::getReadStatus, 0)
|
||||
.geSql(SysMessage::getCreateTime, "DATE_SUB(CURDATE(), INTERVAL 7 DAY)")
|
||||
.leSql(SysMessage::getCreateTime, "DATE_ADD(CURDATE(), INTERVAL 1 DAY)")
|
||||
.count();
|
||||
return success(count);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysRollerAir;
|
||||
import com.agri.system.service.ISysRollerAirService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 自动化卷膜风口大小设置Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-04
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/assets/air")
|
||||
public class SysRollerAirController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysRollerAirService sysRollerAirService;
|
||||
|
||||
/**
|
||||
* 查询自动化卷膜风口大小设置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:air:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysRollerAir sysRollerAir)
|
||||
{
|
||||
startPage();
|
||||
List<SysRollerAir> list = sysRollerAirService.selectSysRollerAirList(sysRollerAir);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出自动化卷膜风口大小设置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:air:export')")
|
||||
@Log(title = "自动化卷膜风口大小设置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysRollerAir sysRollerAir)
|
||||
{
|
||||
List<SysRollerAir> list = sysRollerAirService.selectSysRollerAirList(sysRollerAir);
|
||||
ExcelUtil<SysRollerAir> util = new ExcelUtil<SysRollerAir>(SysRollerAir.class);
|
||||
util.exportExcel(response, list, "自动化卷膜风口大小设置数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取自动化卷膜风口大小设置详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:air:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id)
|
||||
{
|
||||
return success(sysRollerAirService.selectSysRollerAirById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增自动化卷膜风口大小设置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:air:add')")
|
||||
@Log(title = "自动化卷膜风口大小设置", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysRollerAir sysRollerAir)
|
||||
{
|
||||
return toAjax(sysRollerAirService.insertSysRollerAir(sysRollerAir));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改自动化卷膜风口大小设置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:air:edit')")
|
||||
@Log(title = "自动化卷膜风口大小设置", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysRollerAir sysRollerAir)
|
||||
{
|
||||
return toAjax(sysRollerAirService.updateSysRollerAir(sysRollerAir));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除自动化卷膜风口大小设置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:air:remove')")
|
||||
@Log(title = "自动化卷膜风口大小设置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids)
|
||||
{
|
||||
return toAjax(sysRollerAirService.deleteSysRollerAirByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.system.domain.SysRollerParam;
|
||||
import com.agri.system.service.ISysRollerParamService;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
|
||||
/**
|
||||
* 卷膜参数配置Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/control/rollerParam")
|
||||
public class SysRollerParamController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ISysRollerParamService sysRollerParamService;
|
||||
|
||||
/**
|
||||
* 查询卷膜参数配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:rollerParam:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysRollerParam sysRollerParam)
|
||||
{
|
||||
startPage();
|
||||
List<SysRollerParam> list = sysRollerParamService.selectSysRollerParamList(sysRollerParam);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出卷膜参数配置列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:rollerParam:export')")
|
||||
@Log(title = "卷膜参数配置", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysRollerParam sysRollerParam)
|
||||
{
|
||||
List<SysRollerParam> list = sysRollerParamService.selectSysRollerParamList(sysRollerParam);
|
||||
ExcelUtil<SysRollerParam> util = new ExcelUtil<SysRollerParam>(SysRollerParam.class);
|
||||
util.exportExcel(response, list, "卷膜参数配置数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卷膜参数配置详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:rollerParam:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") String id)
|
||||
{
|
||||
return success(sysRollerParamService.selectSysRollerParamById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增卷膜参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:rollerParam:add')")
|
||||
@Log(title = "卷膜参数配置", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysRollerParam sysRollerParam)
|
||||
{
|
||||
return toAjax(sysRollerParamService.insertSysRollerParam(sysRollerParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改卷膜参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:rollerParam:edit')")
|
||||
@Log(title = "卷膜参数配置", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysRollerParam sysRollerParam)
|
||||
{
|
||||
return toAjax(sysRollerParamService.updateSysRollerParam(sysRollerParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除卷膜参数配置
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('control:rollerParam:remove')")
|
||||
@Log(title = "卷膜参数配置", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable String[] ids)
|
||||
{
|
||||
return toAjax(sysRollerParamService.deleteSysRollerParamByIds(ids));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
package com.agri.system.controller;
|
||||
|
||||
import cn.hutool.core.map.MapBuilder;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import com.agri.common.annotation.Log;
|
||||
import com.agri.common.core.controller.BaseController;
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.agri.common.core.page.TableDataInfo;
|
||||
import com.agri.common.enums.BusinessType;
|
||||
import com.agri.common.utils.SecurityUtils;
|
||||
import com.agri.common.utils.poi.ExcelUtil;
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysUserAgri;
|
||||
import com.agri.system.service.ISysUserAgriService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.sql.Wrapper;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 大棚信息(用户-设备关联)Controller
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-25
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/assets/userAgri")
|
||||
public class SysUserAgriController extends BaseController {
|
||||
@Autowired
|
||||
private ISysUserAgriService sysUserAgriService;
|
||||
|
||||
/**
|
||||
* 查询大棚信息(用户-设备关联)列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:list')")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(SysUserAgri sysUserAgri) {
|
||||
startPage();
|
||||
List<SysUserAgri> list = sysUserAgriService.selectSysUserAgriList(sysUserAgri);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出大棚信息(用户-设备关联)列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:export')")
|
||||
@Log(title = "大棚信息(用户-设备关联)", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(HttpServletResponse response, SysUserAgri sysUserAgri) {
|
||||
List<SysUserAgri> list = sysUserAgriService.selectSysUserAgriList(sysUserAgri);
|
||||
ExcelUtil<SysUserAgri> util = new ExcelUtil<SysUserAgri>(SysUserAgri.class);
|
||||
util.exportExcel(response, list, "大棚信息(用户-设备关联)数据");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取大棚信息(用户-设备关联)详细信息
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:query')")
|
||||
@GetMapping(value = "/{id}")
|
||||
public AjaxResult getInfo(@PathVariable("id") Long id) {
|
||||
return success(sysUserAgriService.selectSysUserAgriById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增大棚信息(用户-设备关联)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:add')")
|
||||
@Log(title = "大棚信息(用户-设备关联)", businessType = BusinessType.INSERT)
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody SysUserAgri sysUserAgri) {
|
||||
return toAjax(sysUserAgriService.save(sysUserAgri));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改大棚信息(用户-设备关联)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:edit')")
|
||||
@Log(title = "大棚信息(用户-设备关联)", businessType = BusinessType.UPDATE)
|
||||
@PutMapping
|
||||
public AjaxResult edit(@RequestBody SysUserAgri sysUserAgri) {
|
||||
return toAjax(sysUserAgriService.updateSysUserAgri(sysUserAgri));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除大棚信息(用户-设备关联)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:remove')")
|
||||
@Log(title = "大棚信息(用户-设备关联)", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{ids}")
|
||||
public AjaxResult remove(@PathVariable Long[] ids) {
|
||||
return toAjax(sysUserAgriService.deleteSysUserAgriByIds(ids));
|
||||
}
|
||||
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:list')")
|
||||
@GetMapping("/findAgriUser")
|
||||
public TableDataInfo findAgriUser(SysUserAgri sysUserAgri) {
|
||||
startPage();
|
||||
List<SysUserAgri> list = sysUserAgriService.findAgriUser(sysUserAgri);
|
||||
return getDataTable(list);
|
||||
}
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:list')")
|
||||
@GetMapping("/findAllUser")
|
||||
public TableDataInfo findAllUser(SysUserAgri sysUserAgri) {
|
||||
List<SysUserAgri> list = sysUserAgriService.findAllUser(sysUserAgri);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 新增大棚信息(用户-设备关联)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:add')")
|
||||
@Log(title = "大棚信息(用户-设备批量关联)", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/batchAssociaUser")
|
||||
public AjaxResult batchAssociaUser(@RequestBody List<SysUserAgri> userList) {
|
||||
if (CollectionUtils.isNotEmpty(userList) && !userList.isEmpty()) {
|
||||
String agriId = userList.get(0).getAgriId();
|
||||
if (ObjectUtils.isNotEmpty(agriId)) {
|
||||
QueryWrapper<SysUserAgri> wrapper = new QueryWrapper<>();
|
||||
wrapper.eq("agri_id",agriId);
|
||||
sysUserAgriService.remove(wrapper);
|
||||
|
||||
boolean saveBatch = sysUserAgriService.saveBatch(userList);
|
||||
if (!saveBatch) {
|
||||
return error("更新用户失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除大棚管理
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:remove')")
|
||||
@Log(title = "大棚管理", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/removeAgri")
|
||||
public AjaxResult removeAgri(@RequestBody SysUserAgri userAgri)
|
||||
{
|
||||
if (!SecurityUtils.isAdmin()) {
|
||||
QueryWrapper<SysUserAgri> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("agri_id", userAgri.getImei());
|
||||
queryWrapper.eq("user_id", SecurityUtils.getUserId());
|
||||
boolean remove = sysUserAgriService.remove(queryWrapper);
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近分享的用户
|
||||
* @param sysUserAgri
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('assets:userAgri:list')")
|
||||
@GetMapping("/getRecentShareUser")
|
||||
public AjaxResult getRecentShareUser(SysUserAgri sysUserAgri) {
|
||||
|
||||
return success(sysUserAgriService.getRecentShareUser(sysUserAgri));
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,10 @@ package com.agri.system.domain;
|
|||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.models.auth.In;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
|
|
@ -24,7 +19,6 @@ import java.util.Date;
|
|||
* @author agri
|
||||
* @date 2026-01-08
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_agri_info")
|
||||
public class SysAgriInfo extends BaseEntity
|
||||
{
|
||||
|
|
@ -43,92 +37,198 @@ public class SysAgriInfo extends BaseEntity
|
|||
@Excel(name = "大棚名称")
|
||||
private String agriName;
|
||||
|
||||
/** 工作模式 */
|
||||
@Excel(name = "工作模式")
|
||||
private Integer workMode;
|
||||
|
||||
/** 关联用户ID */
|
||||
@Excel(name = "关联用户ID")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long userId;
|
||||
|
||||
/** 温度上限(℃) */
|
||||
@Excel(name = "温度上限(℃)")
|
||||
private BigDecimal tempUpper;
|
||||
|
||||
/** 温度下限(℃) */
|
||||
@Excel(name = "温度下限(℃)")
|
||||
private BigDecimal tempLower;
|
||||
|
||||
/** 湿度上限(%RH) */
|
||||
@Excel(name = "湿度上限(%RH)")
|
||||
private BigDecimal humiUpper;
|
||||
|
||||
/** 湿度下限(%RH) */
|
||||
@Excel(name = "湿度下限(%RH)")
|
||||
private BigDecimal humiLower;
|
||||
|
||||
/** 告警开关(0-关闭,1-开启) */
|
||||
@Excel(name = "告警开关(0-关闭,1-开启)")
|
||||
private Integer alarmStatus;
|
||||
|
||||
@TableField(exist = false)
|
||||
/** 设备状态(0-离线,1-在线,2-故障) */
|
||||
@Excel(name = "设备状态(0-离线,1-在线,2-故障)")
|
||||
private Integer deviceStatus;
|
||||
|
||||
/** 安装时间 */
|
||||
@Getter
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
@Excel(name = "安装时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date installTime;
|
||||
|
||||
/** 安装位置 */
|
||||
@Setter
|
||||
@Excel(name = "安装位置")
|
||||
private String location;
|
||||
|
||||
/** 逻辑删除(0-未删,1-已删) */
|
||||
@Excel(name = "逻辑删除(0-未删,1-已删)")
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
private Integer isDeleted;
|
||||
|
||||
/**
|
||||
* 来源:0:扫码,1:邀请
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private Integer sourceCode;
|
||||
public void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卷被数量
|
||||
*/
|
||||
private Integer quiltNum;
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卷膜
|
||||
*/
|
||||
private Integer filmNum;
|
||||
public void setImei(String imei)
|
||||
{
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
/**
|
||||
* 卷帘
|
||||
*/
|
||||
private Integer blindNum;
|
||||
public String getImei()
|
||||
{
|
||||
return imei;
|
||||
}
|
||||
|
||||
/** 温度上限(℃) */
|
||||
@Excel(name = "温度上限(℃)")
|
||||
private BigDecimal tempUp;
|
||||
public void setAgriName(String agriName)
|
||||
{
|
||||
this.agriName = agriName;
|
||||
}
|
||||
|
||||
/** 温度下限(℃) */
|
||||
@Excel(name = "温度下限(℃)")
|
||||
private BigDecimal tempLow;
|
||||
public String getAgriName()
|
||||
{
|
||||
return agriName;
|
||||
}
|
||||
|
||||
/** 湿度上限(%RH) */
|
||||
@Excel(name = "湿度上限(%RH)")
|
||||
private BigDecimal humiUp;
|
||||
public void setUserId(Long userId)
|
||||
{
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/** 湿度下限(%RH) */
|
||||
@Excel(name = "湿度下限(%RH)")
|
||||
private BigDecimal humiLow;
|
||||
public Long getUserId()
|
||||
{
|
||||
return userId;
|
||||
}
|
||||
|
||||
@TableField(exist = false)
|
||||
private String title;
|
||||
public void setTempUpper(BigDecimal tempUpper)
|
||||
{
|
||||
this.tempUpper = tempUpper;
|
||||
}
|
||||
|
||||
@TableField(exist = false)
|
||||
private String msg;
|
||||
public BigDecimal getTempUpper()
|
||||
{
|
||||
return tempUpper;
|
||||
}
|
||||
|
||||
@TableField(exist = false)
|
||||
private Integer status;
|
||||
public void setTempLower(BigDecimal tempLower)
|
||||
{
|
||||
this.tempLower = tempLower;
|
||||
}
|
||||
|
||||
/** 关联用户ID */
|
||||
@TableField(exist = false)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long inviteBy;
|
||||
public BigDecimal getTempLower()
|
||||
{
|
||||
return tempLower;
|
||||
}
|
||||
|
||||
/** 已分享次数(非数据库字段,仅用于查询返回) */
|
||||
@TableField(exist = false)
|
||||
private Integer sharedCount;
|
||||
public void setHumiUpper(BigDecimal humiUpper)
|
||||
{
|
||||
this.humiUpper = humiUpper;
|
||||
}
|
||||
|
||||
public BigDecimal getHumiUpper()
|
||||
{
|
||||
return humiUpper;
|
||||
}
|
||||
|
||||
public void setHumiLower(BigDecimal humiLower)
|
||||
{
|
||||
this.humiLower = humiLower;
|
||||
}
|
||||
|
||||
public BigDecimal getHumiLower()
|
||||
{
|
||||
return humiLower;
|
||||
}
|
||||
|
||||
public void setAlarmStatus(Integer alarmStatus)
|
||||
{
|
||||
this.alarmStatus = alarmStatus;
|
||||
}
|
||||
|
||||
public Integer getAlarmStatus()
|
||||
{
|
||||
return alarmStatus;
|
||||
}
|
||||
|
||||
public void setDeviceStatus(Integer deviceStatus)
|
||||
{
|
||||
this.deviceStatus = deviceStatus;
|
||||
}
|
||||
|
||||
public Integer getDeviceStatus()
|
||||
{
|
||||
return deviceStatus;
|
||||
}
|
||||
|
||||
public void setInstallTime(Date installTime)
|
||||
{
|
||||
this.installTime = installTime;
|
||||
}
|
||||
|
||||
public Date getInstallTime()
|
||||
{
|
||||
return installTime;
|
||||
}
|
||||
|
||||
public void setLocation(String location)
|
||||
{
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public String getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
public void setIsDeleted(Integer isDeleted)
|
||||
{
|
||||
this.isDeleted = isDeleted;
|
||||
}
|
||||
|
||||
public Integer getIsDeleted()
|
||||
{
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("agriName", getAgriName())
|
||||
.append("userId", getUserId())
|
||||
.append("tempUpper", getTempUpper())
|
||||
.append("tempLower", getTempLower())
|
||||
.append("humiUpper", getHumiUpper())
|
||||
.append("humiLower", getHumiLower())
|
||||
.append("alarmStatus", getAlarmStatus())
|
||||
.append("deviceStatus", getDeviceStatus())
|
||||
.append("installTime", getInstallTime())
|
||||
.append("location", getLocation())
|
||||
.append("remark", getRemark())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("isDeleted", getIsDeleted())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,14 +50,6 @@ public class SysAgriLimit extends BaseEntity
|
|||
@Excel(name = "卷被关限位时间(秒)")
|
||||
private String jbgLimit;
|
||||
|
||||
/** 卷被开限位时间(秒) */
|
||||
@Excel(name = "卷帘开限位时间(秒)")
|
||||
private String jlkLimit;
|
||||
|
||||
/** 卷被关限位时间(秒) */
|
||||
@Excel(name = "卷帘关限位时间(秒)")
|
||||
private String jlgLimit;
|
||||
|
||||
/** 卷膜1开限位时间(秒) */
|
||||
@Excel(name = "卷膜1开限位时间(秒)")
|
||||
private String jm1kLimit;
|
||||
|
|
@ -96,23 +88,7 @@ public class SysAgriLimit extends BaseEntity
|
|||
@Excel(name = "删除时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date deleteTime;
|
||||
|
||||
public String getJlkLimit() {
|
||||
return jlkLimit;
|
||||
}
|
||||
|
||||
public void setJlkLimit(String jlkLimit) {
|
||||
this.jlkLimit = jlkLimit;
|
||||
}
|
||||
|
||||
public String getJlgLimit() {
|
||||
return jlgLimit;
|
||||
}
|
||||
|
||||
public void setJlgLimit(String jlgLimit) {
|
||||
this.jlgLimit = jlgLimit;
|
||||
}
|
||||
|
||||
public void setId(String id)
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
|
@ -257,8 +233,6 @@ public class SysAgriLimit extends BaseEntity
|
|||
.append("imei", getImei())
|
||||
.append("jbkLimit", getJbkLimit())
|
||||
.append("jbgLimit", getJbgLimit())
|
||||
.append("jlkLimit", getJlkLimit())
|
||||
.append("jlgLimit", getJlgLimit())
|
||||
.append("jm1kLimit", getJm1kLimit())
|
||||
.append("jm1gLimit", getJm1gLimit())
|
||||
.append("jm2kLimit", getJm2kLimit())
|
||||
|
|
|
|||
|
|
@ -1,154 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 大棚功能执行时间限位对象 sys_agri_limit_bak
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
@TableName("sys_agri_limit_bak")
|
||||
public class SysAgriLimitBak extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private String id;
|
||||
|
||||
/** 大棚ID */
|
||||
@Excel(name = "大棚ID")
|
||||
private Long agriId;
|
||||
|
||||
/** 大棚名称 */
|
||||
@Excel(name = "大棚名称")
|
||||
private String agriName;
|
||||
|
||||
/** imei */
|
||||
@Excel(name = "imei")
|
||||
private String imei;
|
||||
|
||||
/** 卷膜 */
|
||||
@Excel(name = "卷膜")
|
||||
private String roller;
|
||||
|
||||
/** 限位时间 */
|
||||
@Excel(name = "限位时间")
|
||||
private BigDecimal funcLimit;
|
||||
|
||||
/** 数据版本号(乐观锁) */
|
||||
@Excel(name = "数据版本号", readConverterExp = "乐=观锁")
|
||||
@Version
|
||||
private String version;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Map<String, BigDecimal> limitMaps;
|
||||
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setAgriId(Long agriId)
|
||||
{
|
||||
this.agriId = agriId;
|
||||
}
|
||||
|
||||
public Long getAgriId()
|
||||
{
|
||||
return agriId;
|
||||
}
|
||||
|
||||
public void setAgriName(String agriName)
|
||||
{
|
||||
this.agriName = agriName;
|
||||
}
|
||||
|
||||
public String getAgriName()
|
||||
{
|
||||
return agriName;
|
||||
}
|
||||
|
||||
public void setImei(String imei)
|
||||
{
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getImei()
|
||||
{
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setRoller(String roller)
|
||||
{
|
||||
this.roller = roller;
|
||||
}
|
||||
|
||||
public String getRoller()
|
||||
{
|
||||
return roller;
|
||||
}
|
||||
|
||||
public BigDecimal getFuncLimit() {
|
||||
return funcLimit;
|
||||
}
|
||||
|
||||
public void setFuncLimit(BigDecimal funcLimit) {
|
||||
this.funcLimit = funcLimit;
|
||||
}
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public Map<String, BigDecimal> getLimitMaps() {
|
||||
return limitMaps;
|
||||
}
|
||||
|
||||
public void setLimitMaps(Map<String, BigDecimal> limitMaps) {
|
||||
this.limitMaps = limitMaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("agriId", getAgriId())
|
||||
.append("agriName", getAgriName())
|
||||
.append("imei", getImei())
|
||||
.append("roller", getRoller())
|
||||
.append("remark", getRemark())
|
||||
.append("version", getVersion())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 卷膜运行条件对象 sys_auto_term
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
@TableName("sys_auto_term")
|
||||
public class SysAutoTerm extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private String id;
|
||||
|
||||
/** imei */
|
||||
@Excel(name = "imei")
|
||||
private String imei;
|
||||
|
||||
/** 卷膜标识 */
|
||||
@Excel(name = "卷膜标识")
|
||||
private String roller;
|
||||
|
||||
/** 运行时间始 */
|
||||
@JsonFormat(pattern = "HH:mm",timezone = "GMT+8")
|
||||
@Excel(name = "运行时间始", width = 30)
|
||||
private Date startTime;
|
||||
|
||||
/** 运行时间止 */
|
||||
@JsonFormat(pattern = "HH:mm",timezone = "GMT+8")
|
||||
@Excel(name = "运行时间止", width = 30)
|
||||
private Date endTime;
|
||||
|
||||
/** 适宜温度 */
|
||||
@Excel(name = "适宜温度")
|
||||
private BigDecimal temp;
|
||||
|
||||
/** 开启风口大小(米) */
|
||||
@Excel(name = "开启风口大小(米)")
|
||||
private Long vent;
|
||||
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setImei(String imei)
|
||||
{
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getImei()
|
||||
{
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setRoller(String roller)
|
||||
{
|
||||
this.roller = roller;
|
||||
}
|
||||
|
||||
public String getRoller()
|
||||
{
|
||||
return roller;
|
||||
}
|
||||
|
||||
public void setStartTime(Date startTime)
|
||||
{
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Date getStartTime()
|
||||
{
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setEndTime(Date endTime)
|
||||
{
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
public Date getEndTime()
|
||||
{
|
||||
return endTime;
|
||||
}
|
||||
|
||||
public void setTemp(BigDecimal temp)
|
||||
{
|
||||
this.temp = temp;
|
||||
}
|
||||
|
||||
public BigDecimal getTemp()
|
||||
{
|
||||
return temp;
|
||||
}
|
||||
|
||||
public void setVent(Long vent)
|
||||
{
|
||||
this.vent = vent;
|
||||
}
|
||||
|
||||
public Long getVent()
|
||||
{
|
||||
return vent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("roller", getRoller())
|
||||
.append("startTime", getStartTime())
|
||||
.append("endTime", getEndTime())
|
||||
.append("temp", getTemp())
|
||||
.append("vent", getVent())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,309 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Builder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
|
||||
/**
|
||||
* 设备控制操作日志对象 sys_dev_oper_log
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@TableName("sys_dev_oper_log")
|
||||
public class SysDevOperLog extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/** 大棚名称 */
|
||||
@Excel(name = "大棚名称")
|
||||
private String agriName;
|
||||
|
||||
/** imei */
|
||||
@Excel(name = "imei")
|
||||
private String imei;
|
||||
|
||||
/** 功能码 */
|
||||
@Excel(name = "功能码")
|
||||
private String funcCode;
|
||||
|
||||
/** 操作类型 */
|
||||
@Excel(name = "操作类型")
|
||||
private Integer opType;
|
||||
|
||||
/** 操作来源 */
|
||||
@Excel(name = "操作来源")
|
||||
private Integer opSource;
|
||||
|
||||
/** 指令 */
|
||||
@Excel(name = "指令")
|
||||
private String payload;
|
||||
|
||||
/** 是否成功获取锁 */
|
||||
@Excel(name = "是否成功获取锁")
|
||||
private Integer lockAcquired;
|
||||
|
||||
/** 锁持有者 */
|
||||
@Excel(name = "锁持有者")
|
||||
private String lockHolder;
|
||||
|
||||
/** 当前任务队列情况 */
|
||||
@Excel(name = "当前任务队列情况")
|
||||
private String taskStatus;
|
||||
|
||||
/** 是否收到设备回执 */
|
||||
@Excel(name = "是否收到设备回执")
|
||||
private Integer ackReceived;
|
||||
|
||||
/** 设备控制是否成功 */
|
||||
@Excel(name = "设备控制是否成功")
|
||||
private Integer ackSuc;
|
||||
|
||||
/** 设备控制锁是否释放成功 */
|
||||
@Excel(name = "设备控制锁是否释放成功")
|
||||
private Integer isLockSuc;
|
||||
|
||||
/** 是否触发定时任务 */
|
||||
@Excel(name = "是否触发定时任务")
|
||||
private Integer isTask;
|
||||
|
||||
@Excel(name = "大棚运行时间限位")
|
||||
private Integer runTime;
|
||||
|
||||
/** 未触发原因 */
|
||||
@Excel(name = "未触发原因")
|
||||
private String noTaskReason;
|
||||
|
||||
/** 设备回执 */
|
||||
@Excel(name = "设备回执")
|
||||
private String ack;
|
||||
|
||||
/** 自动关任务最终执行结果 */
|
||||
@Excel(name = "自动关任务最终执行结果")
|
||||
private Integer execResult;
|
||||
|
||||
/** 未执行原因(如:锁占用、无最新状态、JSON异常) */
|
||||
@Excel(name = "未执行原因", readConverterExp = "如=:锁占用、无最新状态、JSON异常")
|
||||
private String skipReason;
|
||||
|
||||
/** 执行前读取的状态快照 */
|
||||
@Excel(name = "执行前读取的状态快照")
|
||||
private String latestState;
|
||||
|
||||
/** 乐观锁版本号 */
|
||||
@Version
|
||||
private Long version;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getAgriName() {
|
||||
return agriName;
|
||||
}
|
||||
|
||||
public void setAgriName(String agriName) {
|
||||
this.agriName = agriName;
|
||||
}
|
||||
|
||||
public String getImei() {
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setImei(String imei) {
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getFuncCode() {
|
||||
return funcCode;
|
||||
}
|
||||
|
||||
public void setFuncCode(String funcCode) {
|
||||
this.funcCode = funcCode;
|
||||
}
|
||||
|
||||
public Integer getOpType() {
|
||||
return opType;
|
||||
}
|
||||
|
||||
public void setOpType(Integer opType) {
|
||||
this.opType = opType;
|
||||
}
|
||||
|
||||
public Integer getOpSource() {
|
||||
return opSource;
|
||||
}
|
||||
|
||||
public void setOpSource(Integer opSource) {
|
||||
this.opSource = opSource;
|
||||
}
|
||||
|
||||
public String getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(String payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public Integer getLockAcquired() {
|
||||
return lockAcquired;
|
||||
}
|
||||
|
||||
public void setLockAcquired(Integer lockAcquired) {
|
||||
this.lockAcquired = lockAcquired;
|
||||
}
|
||||
|
||||
public String getLockHolder() {
|
||||
return lockHolder;
|
||||
}
|
||||
|
||||
public void setLockHolder(String lockHolder) {
|
||||
this.lockHolder = lockHolder;
|
||||
}
|
||||
|
||||
public String getTaskStatus() {
|
||||
return taskStatus;
|
||||
}
|
||||
|
||||
public void setTaskStatus(String taskStatus) {
|
||||
this.taskStatus = taskStatus;
|
||||
}
|
||||
|
||||
public Integer getAckReceived() {
|
||||
return ackReceived;
|
||||
}
|
||||
|
||||
public void setAckReceived(Integer ackReceived) {
|
||||
this.ackReceived = ackReceived;
|
||||
}
|
||||
|
||||
public Integer getAckSuc() {
|
||||
return ackSuc;
|
||||
}
|
||||
|
||||
public void setAckSuc(Integer ackSuc) {
|
||||
this.ackSuc = ackSuc;
|
||||
}
|
||||
|
||||
public Integer getIsLockSuc() {
|
||||
return isLockSuc;
|
||||
}
|
||||
|
||||
public void setIsLockSuc(Integer isLockSuc) {
|
||||
this.isLockSuc = isLockSuc;
|
||||
}
|
||||
|
||||
public Integer getIsTask() {
|
||||
return isTask;
|
||||
}
|
||||
|
||||
public void setIsTask(Integer isTask) {
|
||||
this.isTask = isTask;
|
||||
}
|
||||
|
||||
public String getNoTaskReason() {
|
||||
return noTaskReason;
|
||||
}
|
||||
|
||||
public void setNoTaskReason(String noTaskReason) {
|
||||
this.noTaskReason = noTaskReason;
|
||||
}
|
||||
|
||||
public String getAck() {
|
||||
return ack;
|
||||
}
|
||||
|
||||
public void setAck(String ack) {
|
||||
this.ack = ack;
|
||||
}
|
||||
|
||||
public Integer getExecResult() {
|
||||
return execResult;
|
||||
}
|
||||
|
||||
public void setExecResult(Integer execResult) {
|
||||
this.execResult = execResult;
|
||||
}
|
||||
|
||||
public String getSkipReason() {
|
||||
return skipReason;
|
||||
}
|
||||
|
||||
public void setSkipReason(String skipReason) {
|
||||
this.skipReason = skipReason;
|
||||
}
|
||||
|
||||
|
||||
public String getLatestState() {
|
||||
return latestState;
|
||||
}
|
||||
|
||||
public void setLatestState(String latestState) {
|
||||
this.latestState = latestState;
|
||||
}
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Integer getRunTime() {
|
||||
return runTime;
|
||||
}
|
||||
|
||||
public void setRunTime(Integer runTime) {
|
||||
this.runTime = runTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("agriName", getAgriName())
|
||||
.append("imei", getImei())
|
||||
.append("funcCode", getFuncCode())
|
||||
.append("opType", getOpType())
|
||||
.append("opSource", getOpSource())
|
||||
.append("payload", getPayload())
|
||||
.append("lockAcquired", getLockAcquired())
|
||||
.append("lockHolder", getLockHolder())
|
||||
.append("taskStatus", getTaskStatus())
|
||||
.append("ackReceived", getAckReceived())
|
||||
.append("ackSuc", getAckSuc())
|
||||
.append("isLockSuc", getIsLockSuc())
|
||||
.append("isTask", getIsTask())
|
||||
.append("runTime", getRunTime())
|
||||
.append("noTaskReason", getNoTaskReason())
|
||||
.append("ack", getAck())
|
||||
.append("execResult", getExecResult())
|
||||
.append("skipReason", getSkipReason())
|
||||
.append("latestState", getLatestState())
|
||||
.append("remark", getRemark())
|
||||
.append("version", getVersion())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,14 +9,13 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
|
|||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* DTU温湿度上报数据对象 sys_dtu_data
|
||||
*
|
||||
*
|
||||
* @author agri
|
||||
* @LocalDateTime 2025-12-23
|
||||
* @date 2025-12-23
|
||||
*/
|
||||
public class SysDtuData extends BaseEntity
|
||||
{
|
||||
|
|
@ -37,7 +36,7 @@ public class SysDtuData extends BaseEntity
|
|||
/** ts转换后的正常时间(由服务端转换入库) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
@Excel(name = "ts转换后的正常时间(由服务端转换入库)", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private LocalDateTime time;
|
||||
private Date time;
|
||||
|
||||
/** 温度1(℃) */
|
||||
@Excel(name = "温度1(℃)")
|
||||
|
|
@ -75,132 +74,132 @@ public class SysDtuData extends BaseEntity
|
|||
@Excel(name = "原始JSON元信息(原始上报码/额外字段)")
|
||||
private String raw;
|
||||
|
||||
public void setId(Long id)
|
||||
public void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getId()
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setImei(String imei)
|
||||
public void setImei(String imei)
|
||||
{
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getImei()
|
||||
public String getImei()
|
||||
{
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setTs(Long ts)
|
||||
public void setTs(Long ts)
|
||||
{
|
||||
this.ts = ts;
|
||||
}
|
||||
|
||||
public Long getTs()
|
||||
public Long getTs()
|
||||
{
|
||||
return ts;
|
||||
}
|
||||
|
||||
public void setTime(LocalDateTime time)
|
||||
public void setTime(Date time)
|
||||
{
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
public LocalDateTime getTime()
|
||||
public Date getTime()
|
||||
{
|
||||
return time;
|
||||
}
|
||||
|
||||
public void setTemp1(BigDecimal temp1)
|
||||
public void setTemp1(BigDecimal temp1)
|
||||
{
|
||||
this.temp1 = temp1;
|
||||
}
|
||||
|
||||
public BigDecimal getTemp1()
|
||||
public BigDecimal getTemp1()
|
||||
{
|
||||
return temp1;
|
||||
}
|
||||
|
||||
public void setHumi1(BigDecimal humi1)
|
||||
public void setHumi1(BigDecimal humi1)
|
||||
{
|
||||
this.humi1 = humi1;
|
||||
}
|
||||
|
||||
public BigDecimal getHumi1()
|
||||
public BigDecimal getHumi1()
|
||||
{
|
||||
return humi1;
|
||||
}
|
||||
|
||||
public void setTemp2(BigDecimal temp2)
|
||||
public void setTemp2(BigDecimal temp2)
|
||||
{
|
||||
this.temp2 = temp2;
|
||||
}
|
||||
|
||||
public BigDecimal getTemp2()
|
||||
public BigDecimal getTemp2()
|
||||
{
|
||||
return temp2;
|
||||
}
|
||||
|
||||
public void setHumi2(BigDecimal humi2)
|
||||
public void setHumi2(BigDecimal humi2)
|
||||
{
|
||||
this.humi2 = humi2;
|
||||
}
|
||||
|
||||
public BigDecimal getHumi2()
|
||||
public BigDecimal getHumi2()
|
||||
{
|
||||
return humi2;
|
||||
}
|
||||
|
||||
public void setTemp3(BigDecimal temp3)
|
||||
public void setTemp3(BigDecimal temp3)
|
||||
{
|
||||
this.temp3 = temp3;
|
||||
}
|
||||
|
||||
public BigDecimal getTemp3()
|
||||
public BigDecimal getTemp3()
|
||||
{
|
||||
return temp3;
|
||||
}
|
||||
|
||||
public void setHumi3(BigDecimal humi3)
|
||||
public void setHumi3(BigDecimal humi3)
|
||||
{
|
||||
this.humi3 = humi3;
|
||||
}
|
||||
|
||||
public BigDecimal getHumi3()
|
||||
public BigDecimal getHumi3()
|
||||
{
|
||||
return humi3;
|
||||
}
|
||||
|
||||
public void setTemp4(BigDecimal temp4)
|
||||
public void setTemp4(BigDecimal temp4)
|
||||
{
|
||||
this.temp4 = temp4;
|
||||
}
|
||||
|
||||
public BigDecimal getTemp4()
|
||||
public BigDecimal getTemp4()
|
||||
{
|
||||
return temp4;
|
||||
}
|
||||
|
||||
public void setHumi4(BigDecimal humi4)
|
||||
public void setHumi4(BigDecimal humi4)
|
||||
{
|
||||
this.humi4 = humi4;
|
||||
}
|
||||
|
||||
public BigDecimal getHumi4()
|
||||
public BigDecimal getHumi4()
|
||||
{
|
||||
return humi4;
|
||||
}
|
||||
|
||||
public void setRaw(String raw)
|
||||
public void setRaw(String raw)
|
||||
{
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public String getRaw()
|
||||
public String getRaw()
|
||||
{
|
||||
return raw;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,14 +36,6 @@ public class SysDtuRemark extends BaseEntity
|
|||
@Excel(name = "卷被关")
|
||||
private String jbg;
|
||||
|
||||
/** 卷被开 */
|
||||
@Excel(name = "卷帘开")
|
||||
private String jlk;
|
||||
|
||||
/** 卷被关 */
|
||||
@Excel(name = "卷帘关")
|
||||
private String jlg;
|
||||
|
||||
/** 卷膜1开 */
|
||||
@Excel(name = "卷膜1开")
|
||||
private String jm1k;
|
||||
|
|
@ -308,29 +300,11 @@ public class SysDtuRemark extends BaseEntity
|
|||
return extJson;
|
||||
}
|
||||
|
||||
public String getJlk() {
|
||||
return jlk;
|
||||
}
|
||||
|
||||
public void setJlk(String jlk) {
|
||||
this.jlk = jlk;
|
||||
}
|
||||
|
||||
public String getJlg() {
|
||||
return jlg;
|
||||
}
|
||||
|
||||
public void setJlg(String jlg) {
|
||||
this.jlg = jlg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("jlk", getJlk())
|
||||
.append("jlg", getJlg())
|
||||
.append("jbk", getJbk())
|
||||
.append("jbg", getJbg())
|
||||
.append("jm1k", getJm1k())
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* dtu设备备注对象 sys_dtu_remark_bak
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
@TableName("sys_dtu_remark_bak")
|
||||
public class SysDtuRemarkBak extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private String id;
|
||||
|
||||
/** imei */
|
||||
@Excel(name = "imei")
|
||||
private String imei;
|
||||
|
||||
/** 类型 */
|
||||
@Excel(name = "类型")
|
||||
private String roller;
|
||||
|
||||
/** 备注 */
|
||||
@Excel(name = "备注")
|
||||
private String remarkShort;
|
||||
|
||||
/** 数据版本号(乐观锁) */
|
||||
@Excel(name = "数据版本号", readConverterExp = "乐=观锁")
|
||||
@Version
|
||||
private String version;
|
||||
|
||||
/** 扩展备注 */
|
||||
private String extJson;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Map<String, String> remarkMaps;
|
||||
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setImei(String imei)
|
||||
{
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getImei()
|
||||
{
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setRoller(String roller)
|
||||
{
|
||||
this.roller = roller;
|
||||
}
|
||||
|
||||
public String getRoller()
|
||||
{
|
||||
return roller;
|
||||
}
|
||||
|
||||
public void setRemarkShort(String remarkShort)
|
||||
{
|
||||
this.remarkShort = remarkShort;
|
||||
}
|
||||
|
||||
public String getRemarkShort()
|
||||
{
|
||||
return remarkShort;
|
||||
}
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setExtJson(String extJson)
|
||||
{
|
||||
this.extJson = extJson;
|
||||
}
|
||||
|
||||
public String getExtJson()
|
||||
{
|
||||
return extJson;
|
||||
}
|
||||
|
||||
public Map<String, String> getRemarkMaps() {
|
||||
return remarkMaps;
|
||||
}
|
||||
|
||||
public void setRemarkMaps(Map<String, String> remarkMaps) {
|
||||
this.remarkMaps = remarkMaps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("roller", getRoller())
|
||||
.append("remarkShort", getRemarkShort())
|
||||
.append("version", getVersion())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.append("extJson", getExtJson())
|
||||
.append("remark", getRemark())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,210 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
/**
|
||||
* 自动模式日志对象 sys_imei_auto_log
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-29
|
||||
*/
|
||||
@TableName("sys_imei_auto_log")
|
||||
public class SysImeiAutoLog extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键 */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/** 设备IMEI */
|
||||
@Excel(name = "设备IMEI")
|
||||
private String imei;
|
||||
|
||||
/** 卷膜 */
|
||||
@Excel(name = "卷膜")
|
||||
private String rollFilm;
|
||||
|
||||
/** 监控时间段 */
|
||||
@Excel(name = "监控时间段")
|
||||
private String monitorPeriod;
|
||||
|
||||
/** 当前温度 */
|
||||
@Excel(name = "当前温度")
|
||||
private BigDecimal currentTemp;
|
||||
|
||||
/** 参考温度 */
|
||||
@Excel(name = "参考温度")
|
||||
private String refTemp;
|
||||
|
||||
/** 适宜温度 */
|
||||
@Excel(name = "适宜温度")
|
||||
private BigDecimal suitableTemp;
|
||||
|
||||
/** 运行风口 */
|
||||
@Excel(name = "运行风口")
|
||||
private BigDecimal fanStatus;
|
||||
|
||||
/** 是否最后一条 0否1是 */
|
||||
@Excel(name = "是否最后一条 0否1是")
|
||||
private int isLast;
|
||||
|
||||
/** 执行指令 */
|
||||
@Excel(name = "执行指令")
|
||||
private String execCmd;
|
||||
|
||||
/** 操作日志ID */
|
||||
@Excel(name = "操作日志ID")
|
||||
private Long logId;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
|
||||
private LocalDate monitorDate;
|
||||
|
||||
public LocalDate getMonitorDate() {
|
||||
return monitorDate;
|
||||
}
|
||||
|
||||
public void setMonitorDate(LocalDate monitorDate) {
|
||||
this.monitorDate = monitorDate;
|
||||
}
|
||||
|
||||
public void setId(Long id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setImei(String imei)
|
||||
{
|
||||
this.imei = imei;
|
||||
}
|
||||
|
||||
public String getImei()
|
||||
{
|
||||
return imei;
|
||||
}
|
||||
|
||||
public void setRollFilm(String rollFilm)
|
||||
{
|
||||
this.rollFilm = rollFilm;
|
||||
}
|
||||
|
||||
public String getRollFilm()
|
||||
{
|
||||
return rollFilm;
|
||||
}
|
||||
|
||||
public void setMonitorPeriod(String monitorPeriod)
|
||||
{
|
||||
this.monitorPeriod = monitorPeriod;
|
||||
}
|
||||
|
||||
public String getMonitorPeriod()
|
||||
{
|
||||
return monitorPeriod;
|
||||
}
|
||||
|
||||
public void setCurrentTemp(BigDecimal currentTemp)
|
||||
{
|
||||
this.currentTemp = currentTemp;
|
||||
}
|
||||
|
||||
public BigDecimal getCurrentTemp()
|
||||
{
|
||||
return currentTemp;
|
||||
}
|
||||
|
||||
public String getRefTemp() {
|
||||
return refTemp;
|
||||
}
|
||||
|
||||
public void setRefTemp(String refTemp) {
|
||||
this.refTemp = refTemp;
|
||||
}
|
||||
|
||||
public BigDecimal getSuitableTemp() {
|
||||
return suitableTemp;
|
||||
}
|
||||
|
||||
public void setSuitableTemp(BigDecimal suitableTemp) {
|
||||
this.suitableTemp = suitableTemp;
|
||||
}
|
||||
|
||||
public BigDecimal getFanStatus() {
|
||||
return fanStatus;
|
||||
}
|
||||
|
||||
public void setFanStatus(BigDecimal fanStatus) {
|
||||
this.fanStatus = fanStatus;
|
||||
}
|
||||
|
||||
|
||||
public int getIsLast() {
|
||||
return isLast;
|
||||
}
|
||||
|
||||
public void setIsLast(int isLast) {
|
||||
this.isLast = isLast;
|
||||
}
|
||||
|
||||
public void setExecCmd(String execCmd)
|
||||
{
|
||||
this.execCmd = execCmd;
|
||||
}
|
||||
|
||||
public String getExecCmd()
|
||||
{
|
||||
return execCmd;
|
||||
}
|
||||
|
||||
public void setLogId(Long logId)
|
||||
{
|
||||
this.logId = logId;
|
||||
}
|
||||
|
||||
public Long getLogId()
|
||||
{
|
||||
return logId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("rollFilm", getRollFilm())
|
||||
.append("monitorPeriod", getMonitorPeriod())
|
||||
.append("currentTemp", getCurrentTemp())
|
||||
.append("refTemp", getRefTemp())
|
||||
.append("suitableTemp", getSuitableTemp())
|
||||
.append("fanStatus", getFanStatus())
|
||||
.append("isLast", getIsLast())
|
||||
.append("execCmd", getExecCmd())
|
||||
.append("logId", getLogId())
|
||||
.append("remark", getRemark())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统消息中心对象 sys_message
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-26
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_message")
|
||||
public class SysMessage extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 消息主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
private String imei;
|
||||
/** 接收人:all=全体用户,其他=用户ID */
|
||||
@Excel(name = "接收人:all=全体用户,其他=用户ID")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long receiver;
|
||||
|
||||
/** 消息标题 */
|
||||
@Excel(name = "消息标题")
|
||||
private String title;
|
||||
|
||||
/** 消息类型:activity-活动 notice-通知 interact-互动消息 */
|
||||
@Excel(name = "消息类型:status-状态,notice-通知,event-活动")
|
||||
private String msgType;
|
||||
|
||||
/** 阅读状态:0-未读 1-已读 */
|
||||
@Excel(name = "阅读状态:0-未读 1-已读")
|
||||
private Long readStatus;
|
||||
|
||||
/** 消息内容(普通文本) */
|
||||
@Excel(name = "消息内容", readConverterExp = "普=通文本")
|
||||
private String content;
|
||||
|
||||
/** 富文本内容 */
|
||||
@Excel(name = "富文本内容")
|
||||
private String richContent;
|
||||
|
||||
/** 图片地址 */
|
||||
@Excel(name = "图片地址")
|
||||
private String imgUrl;
|
||||
|
||||
/** 跳转链接地址 */
|
||||
@Excel(name = "跳转链接地址")
|
||||
private String linkUrl;
|
||||
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
|
||||
private LocalDate monitorDate;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<String> imeiList;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long sortOldId;
|
||||
|
||||
@TableField(exist = false)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long sortNewId;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Integer unreadCount;
|
||||
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 自动化卷膜风口大小设置对象 sys_roller_air
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-04
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_roller_air")
|
||||
public class SysRollerAir extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/** 设备IMEI码 */
|
||||
@Excel(name = "设备IMEI码")
|
||||
private String imei;
|
||||
|
||||
/** 卷膜器编号/标识 */
|
||||
@Excel(name = "卷膜器编号/标识")
|
||||
private String roller;
|
||||
|
||||
/** 操作类型 0-停止 1-运行 2-查询 3-重置 */
|
||||
@Excel(name = "操作类型 0-停止 1-运行 2-查询 3-重置")
|
||||
private Integer opType;
|
||||
|
||||
/** 操作参数(JSON格式,存储风口大小等配置) */
|
||||
@Excel(name = "操作参数(JSON格式,存储风口大小等配置)")
|
||||
private String payload;
|
||||
|
||||
/** 客户端ID */
|
||||
@Excel(name = "客户端ID")
|
||||
private String clientid;
|
||||
|
||||
/** 操作执行时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
@Excel(name = "操作执行时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private LocalDateTime opTime;
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("roller", getRoller())
|
||||
.append("opType", getOpType())
|
||||
.append("payload", getPayload())
|
||||
.append("clientid", getClientid())
|
||||
.append("opTime", getOpTime())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 卷膜参数配置对象 sys_roller_param
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_roller_param")
|
||||
public class SysRollerParam extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private String id;
|
||||
|
||||
/** imei */
|
||||
@Excel(name = "imei")
|
||||
private String imei;
|
||||
|
||||
/** 卷膜标识 */
|
||||
@Excel(name = "卷膜标识")
|
||||
private String roller;
|
||||
|
||||
/** 参考温度 */
|
||||
@Excel(name = "参考温度")
|
||||
private String refTempCode;
|
||||
/** 参考温度 */
|
||||
@TableField(exist = false)
|
||||
@Excel(name = "参考温度")
|
||||
private String refTemp;
|
||||
|
||||
/** 预留风口长度(cm) */
|
||||
@Excel(name = "预留风口长度(cm)")
|
||||
private BigDecimal reservedLen;
|
||||
|
||||
/** 手动计算风口总长(cm) */
|
||||
@Excel(name = "手动计算风口总长(cm)")
|
||||
private BigDecimal manualTotalLen;
|
||||
|
||||
/** 自动计算风口总长(cm) */
|
||||
@Excel(name = "自动计算风口总长(cm)")
|
||||
private BigDecimal autoTotalLen;
|
||||
|
||||
@Excel(name = "最终风口总长")
|
||||
private BigDecimal ventTotalLen;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
.append("id", getId())
|
||||
.append("imei", getImei())
|
||||
.append("roller", getRoller())
|
||||
.append("refTempCode", getRefTempCode())
|
||||
.append("reservedLen", getReservedLen())
|
||||
.append("manualTotalLen", getManualTotalLen())
|
||||
.append("autoTotalLen", getAutoTotalLen())
|
||||
.append("createBy", getCreateBy())
|
||||
.append("createTime", getCreateTime())
|
||||
.append("updateBy", getUpdateBy())
|
||||
.append("updateTime", getUpdateTime())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
package com.agri.system.domain;
|
||||
|
||||
import com.agri.common.annotation.Excel;
|
||||
import com.agri.common.core.domain.BaseEntity;
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.annotation.Version;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 大棚信息(用户-设备关联)对象 sys_user_agri
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-25
|
||||
*/
|
||||
@Data
|
||||
@TableName("sys_user_agri")
|
||||
public class SysUserAgri extends BaseEntity
|
||||
{
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID(雪花) */
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/** 大棚ID */
|
||||
@Excel(name = "大棚ID")
|
||||
private String agriId;
|
||||
|
||||
/** 大棚名称 */
|
||||
@Excel(name = "大棚名称")
|
||||
private String agriName;
|
||||
|
||||
/** 协同用户ID */
|
||||
@Excel(name = "协同用户ID")
|
||||
private Long userId;
|
||||
|
||||
/** 角色:3-OWNER/2-ADMIN/1-OPERATOR/0-VIEWER */
|
||||
@Excel(name = "角色:3-OWNER/2-ADMIN/1-OPERATOR/0-VIEWER")
|
||||
private Integer role;
|
||||
|
||||
/** 权限位(位运算):1=查看 2=控制 4=配置 8=分享/成员管理 16=导出等 */
|
||||
@Excel(name = "权限位", readConverterExp = "位=运算")
|
||||
private Integer permMask;
|
||||
|
||||
/** 状态:0=禁用 1=启用 2=待接受邀请 */
|
||||
@Excel(name = "状态:0=禁用 1=启用 2=待接受邀请")
|
||||
private Integer status;
|
||||
|
||||
/** 邀请人用户ID */
|
||||
@Excel(name = "邀请人用户ID")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long inviteBy;
|
||||
|
||||
/** 邀请时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
@Excel(name = "邀请时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date inviteTime;
|
||||
|
||||
/** 接受时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
@Excel(name = "接受时间", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date acceptTime;
|
||||
|
||||
/** 版本号(乐观锁) */
|
||||
@Excel(name = "版本号", readConverterExp = "乐=观锁")
|
||||
@Version
|
||||
private Integer version;
|
||||
|
||||
@TableField(exist = false)
|
||||
private SysUser sysUser;
|
||||
|
||||
@TableField(exist = false)
|
||||
private String imei;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Boolean disabled;
|
||||
|
||||
@TableField(exist = false)
|
||||
private List<String> imeiList;
|
||||
|
||||
public SysUserAgri(List<String> imeiList, Integer status) {
|
||||
this.imeiList = imeiList;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public SysUserAgri() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
package com.agri.system.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @ClassName AgriAutoInfoVo
|
||||
* @Description TODO
|
||||
* @Author lld
|
||||
* @Date 2026/3/5 22:07
|
||||
* @Version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class AgriAutoInfoVo {
|
||||
|
||||
/** 设备IMEI */
|
||||
private String imei;
|
||||
|
||||
/** 大棚名称 */
|
||||
private String agriName;
|
||||
|
||||
/** 工作模式 */
|
||||
private Integer workMode;
|
||||
|
||||
/** 逻辑删除(0-未删,1-已删) */
|
||||
private Integer isDeleted;
|
||||
|
||||
/** 卷膜标识 */
|
||||
private String roller;
|
||||
|
||||
/** 参考温度 */
|
||||
private String refTempCode;
|
||||
|
||||
/** 参考温度 */
|
||||
private String refTemp;
|
||||
|
||||
/** 预留风口长度(cm) */
|
||||
private BigDecimal reservedLen;
|
||||
|
||||
/** 手动计算风口总长(cm) */
|
||||
private BigDecimal manualTotalLen;
|
||||
|
||||
/** 自动计算风口总长(cm) */
|
||||
private BigDecimal autoTotalLen;
|
||||
|
||||
private BigDecimal ventTotalLen;
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package com.agri.system.domain.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class AgriInfoView {
|
||||
|
||||
/** 主键ID */
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/** 设备IMEI */
|
||||
private String imei;
|
||||
|
||||
/** 大棚名称 */
|
||||
private String agriName;
|
||||
|
||||
/** 工作模式 */
|
||||
private Integer workMode;
|
||||
|
||||
/** 设备状态(0-离线,1-在线,2-故障) */
|
||||
private Integer deviceStatus;
|
||||
|
||||
/** 关联用户ID */
|
||||
private Long userId;
|
||||
|
||||
/** ts转换后的正常时间(由服务端转换入库) */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
|
||||
private Date time;
|
||||
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long ts;
|
||||
|
||||
/** 温度1(℃) */
|
||||
private BigDecimal temp1;
|
||||
|
||||
/** 温度2(℃) */
|
||||
private BigDecimal temp2;
|
||||
|
||||
/** 温度3(℃) */
|
||||
private BigDecimal temp3;
|
||||
|
||||
/** 温度4(℃) */
|
||||
private BigDecimal temp4;
|
||||
|
||||
|
||||
/**
|
||||
* 卷被数量
|
||||
*/
|
||||
private Integer quiltNum;
|
||||
|
||||
/**
|
||||
* 卷膜
|
||||
*/
|
||||
private Integer filmNum;
|
||||
|
||||
/**
|
||||
* 卷帘
|
||||
*/
|
||||
private Integer blindNum;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package com.agri.system.domain.vo;
|
||||
|
||||
import com.agri.system.domain.SysAutoTerm;
|
||||
import com.agri.system.domain.SysRollerParam;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自动化条件vo
|
||||
*/
|
||||
@Data
|
||||
public class AgriTermVo {
|
||||
|
||||
private SysRollerParam config;
|
||||
|
||||
private List<SysAutoTerm> terms;
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
package com.agri.system.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @ClassName RollerTermVO
|
||||
* @Description TODO
|
||||
* @Author lld
|
||||
* @Date 2026/3/6 1:13
|
||||
* @Version 1.0
|
||||
*/
|
||||
// 用于承接rollerParam+autoTerms关联查询的结果
|
||||
@Data
|
||||
public class RollerTermVO {
|
||||
// rollerParam字段
|
||||
private String imei;
|
||||
private String roller;
|
||||
private String refTempCode;
|
||||
private BigDecimal reservedLen;
|
||||
private BigDecimal manualTotalLen;
|
||||
private BigDecimal autoTotalLen;
|
||||
private BigDecimal ventTotalLen;
|
||||
|
||||
// autoTerms字段(一对多,允许为null)
|
||||
private BigDecimal temp;
|
||||
private BigDecimal vent;
|
||||
private LocalDateTime startTime;
|
||||
private LocalDateTime endTime;
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package com.agri.system.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class UChartsDataView {
|
||||
|
||||
// X轴分类(时间)
|
||||
private List<String> categories;
|
||||
// 系列数据(温度/湿度)
|
||||
private List<UChartsSeries> series;
|
||||
|
||||
@Data
|
||||
// 内部类:单条系列数据
|
||||
public static class UChartsSeries {
|
||||
private String name; // 系列名称(如"温度1")
|
||||
private Boolean show; // 系列名称(如"温度1")
|
||||
private BigDecimal index;
|
||||
private List<BigDecimal> data; // 系列数值
|
||||
|
||||
public UChartsSeries() {
|
||||
}
|
||||
|
||||
public UChartsSeries(String name, Boolean show, BigDecimal index, List<BigDecimal> data) {
|
||||
this.name = name;
|
||||
this.show = show;
|
||||
this.index = index;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public UChartsDataView() {
|
||||
}
|
||||
|
||||
public UChartsDataView(List<String> categories, List<UChartsSeries> series) {
|
||||
this.categories = categories;
|
||||
this.series = series;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,21 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.vo.AgriAutoInfoVo;
|
||||
import com.agri.system.domain.vo.AgriInfoView;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 大棚管理Mapper接口
|
||||
*
|
||||
*
|
||||
* @author agri
|
||||
* @date 2026-01-08
|
||||
*/
|
||||
public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo> {
|
||||
public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo>
|
||||
{
|
||||
/**
|
||||
* 查询大棚管理
|
||||
*
|
||||
*
|
||||
* @param id 大棚管理主键
|
||||
* @return 大棚管理
|
||||
*/
|
||||
|
|
@ -25,7 +23,7 @@ public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 查询大棚管理列表
|
||||
*
|
||||
*
|
||||
* @param sysAgriInfo 大棚管理
|
||||
* @return 大棚管理集合
|
||||
*/
|
||||
|
|
@ -33,7 +31,7 @@ public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 新增大棚管理
|
||||
*
|
||||
*
|
||||
* @param sysAgriInfo 大棚管理
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -41,7 +39,7 @@ public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 修改大棚管理
|
||||
*
|
||||
*
|
||||
* @param sysAgriInfo 大棚管理
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -49,7 +47,7 @@ public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 删除大棚管理
|
||||
*
|
||||
*
|
||||
* @param id 大棚管理主键
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -57,28 +55,9 @@ public interface SysAgriInfoMapper extends BaseMapper<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 批量删除大棚管理
|
||||
*
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAgriInfoByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 查当前用户下的大棚
|
||||
* @param sysAgriInfo
|
||||
* @return
|
||||
*/
|
||||
public List<SysAgriInfo> findAgriByUser(SysAgriInfo sysAgriInfo);
|
||||
|
||||
|
||||
public List<AgriInfoView> findAgriInfoByUser(SysAgriInfo sysAgriInfo);
|
||||
|
||||
List<AgriAutoInfoVo> findAgriOfAutoInfo();
|
||||
|
||||
/**
|
||||
* 查询设备分享列表(我的分享 + 分享给我的),带shared_count
|
||||
* @param sysAgriInfo 查询条件
|
||||
* @return 设备分享列表
|
||||
*/
|
||||
List<SysAgriInfo> selectShareList(SysAgriInfo sysAgriInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysAgriLimitBak;
|
||||
|
||||
/**
|
||||
* 大棚功能执行时间限位Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
public interface SysAgriLimitBakMapper extends BaseMapper<SysAgriLimitBak>
|
||||
{
|
||||
/**
|
||||
* 查询大棚功能执行时间限位
|
||||
*
|
||||
* @param id 大棚功能执行时间限位主键
|
||||
* @return 大棚功能执行时间限位
|
||||
*/
|
||||
public SysAgriLimitBak selectSysAgriLimitBakById(String id);
|
||||
|
||||
/**
|
||||
* 查询大棚功能执行时间限位列表
|
||||
*
|
||||
* @param sysAgriLimitBak 大棚功能执行时间限位
|
||||
* @return 大棚功能执行时间限位集合
|
||||
*/
|
||||
public List<SysAgriLimitBak> selectSysAgriLimitBakList(SysAgriLimitBak sysAgriLimitBak);
|
||||
|
||||
/**
|
||||
* 新增大棚功能执行时间限位
|
||||
*
|
||||
* @param sysAgriLimitBak 大棚功能执行时间限位
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysAgriLimitBak(SysAgriLimitBak sysAgriLimitBak);
|
||||
|
||||
/**
|
||||
* 修改大棚功能执行时间限位
|
||||
*
|
||||
* @param sysAgriLimitBak 大棚功能执行时间限位
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysAgriLimitBak(SysAgriLimitBak sysAgriLimitBak);
|
||||
|
||||
/**
|
||||
* 删除大棚功能执行时间限位
|
||||
*
|
||||
* @param id 大棚功能执行时间限位主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAgriLimitBakById(String id);
|
||||
|
||||
/**
|
||||
* 批量删除大棚功能执行时间限位
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAgriLimitBakByIds(String[] ids);
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysAutoTerm;
|
||||
|
||||
/**
|
||||
* 卷膜运行条件Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
public interface SysAutoTermMapper extends BaseMapper<SysAutoTerm>
|
||||
{
|
||||
/**
|
||||
* 查询卷膜运行条件
|
||||
*
|
||||
* @param id 卷膜运行条件主键
|
||||
* @return 卷膜运行条件
|
||||
*/
|
||||
public SysAutoTerm selectSysAutoTermById(String id);
|
||||
|
||||
/**
|
||||
* 查询卷膜运行条件列表
|
||||
*
|
||||
* @param sysAutoTerm 卷膜运行条件
|
||||
* @return 卷膜运行条件集合
|
||||
*/
|
||||
public List<SysAutoTerm> selectSysAutoTermList(SysAutoTerm sysAutoTerm);
|
||||
|
||||
/**
|
||||
* 新增卷膜运行条件
|
||||
*
|
||||
* @param sysAutoTerm 卷膜运行条件
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysAutoTerm(SysAutoTerm sysAutoTerm);
|
||||
|
||||
/**
|
||||
* 修改卷膜运行条件
|
||||
*
|
||||
* @param sysAutoTerm 卷膜运行条件
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysAutoTerm(SysAutoTerm sysAutoTerm);
|
||||
|
||||
/**
|
||||
* 删除卷膜运行条件
|
||||
*
|
||||
* @param id 卷膜运行条件主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAutoTermById(String id);
|
||||
|
||||
/**
|
||||
* 批量删除卷膜运行条件
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAutoTermByIds(String[] ids);
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
|
||||
/**
|
||||
* 设备控制操作日志Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
public interface SysDevOperLogMapper extends BaseMapper<SysDevOperLog>
|
||||
{
|
||||
/**
|
||||
* 查询设备控制操作日志
|
||||
*
|
||||
* @param id 设备控制操作日志主键
|
||||
* @return 设备控制操作日志
|
||||
*/
|
||||
public SysDevOperLog selectSysDevOperLogById(Long id);
|
||||
|
||||
/**
|
||||
* 查询设备控制操作日志列表
|
||||
*
|
||||
* @param sysDevOperLog 设备控制操作日志
|
||||
* @return 设备控制操作日志集合
|
||||
*/
|
||||
public List<SysDevOperLog> selectSysDevOperLogList(SysDevOperLog sysDevOperLog);
|
||||
|
||||
/**
|
||||
* 新增设备控制操作日志
|
||||
*
|
||||
* @param sysDevOperLog 设备控制操作日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysDevOperLog(SysDevOperLog sysDevOperLog);
|
||||
|
||||
/**
|
||||
* 修改设备控制操作日志
|
||||
*
|
||||
* @param sysDevOperLog 设备控制操作日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysDevOperLog(SysDevOperLog sysDevOperLog);
|
||||
|
||||
/**
|
||||
* 删除设备控制操作日志
|
||||
*
|
||||
* @param id 设备控制操作日志主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDevOperLogById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除设备控制操作日志
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDevOperLogByIds(Long[] ids);
|
||||
}
|
||||
|
|
@ -1,13 +1,7 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.agri.system.domain.SysAgriAlarmRelation;
|
||||
import com.agri.system.domain.SysDtuData;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* DTU温湿度上报数据Mapper接口
|
||||
|
|
@ -15,7 +9,7 @@ import org.apache.ibatis.annotations.Param;
|
|||
* @author agri
|
||||
* @date 2025-12-23
|
||||
*/
|
||||
public interface SysDtuDataMapper extends BaseMapper<SysDtuData>
|
||||
public interface SysDtuDataMapper
|
||||
{
|
||||
/**
|
||||
* 查询DTU温湿度上报数据
|
||||
|
|
@ -66,14 +60,4 @@ public interface SysDtuDataMapper extends BaseMapper<SysDtuData>
|
|||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDtuDataByIds(Long[] ids);
|
||||
|
||||
List<Map<String, Object>> getLastDtuDataByImeiList(@Param("imeiList") List<String> imeiList);
|
||||
|
||||
|
||||
List<SysDtuData> getHistoryData(
|
||||
@Param("imei") String imei,
|
||||
@Param("startTime") LocalDateTime startTime,
|
||||
@Param("endTime") LocalDateTime endTime
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysDtuRemarkBak;
|
||||
|
||||
/**
|
||||
* dtu设备备注Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
public interface SysDtuRemarkBakMapper extends BaseMapper<SysDtuRemarkBak>
|
||||
{
|
||||
/**
|
||||
* 查询dtu设备备注
|
||||
*
|
||||
* @param id dtu设备备注主键
|
||||
* @return dtu设备备注
|
||||
*/
|
||||
public SysDtuRemarkBak selectSysDtuRemarkBakById(String id);
|
||||
|
||||
/**
|
||||
* 查询dtu设备备注列表
|
||||
*
|
||||
* @param sysDtuRemarkBak dtu设备备注
|
||||
* @return dtu设备备注集合
|
||||
*/
|
||||
public List<SysDtuRemarkBak> selectSysDtuRemarkBakList(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
|
||||
/**
|
||||
* 新增dtu设备备注
|
||||
*
|
||||
* @param sysDtuRemarkBak dtu设备备注
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysDtuRemarkBak(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
|
||||
/**
|
||||
* 修改dtu设备备注
|
||||
*
|
||||
* @param sysDtuRemarkBak dtu设备备注
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysDtuRemarkBak(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
|
||||
/**
|
||||
* 删除dtu设备备注
|
||||
*
|
||||
* @param id dtu设备备注主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDtuRemarkBakById(String id);
|
||||
|
||||
/**
|
||||
* 批量删除dtu设备备注
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDtuRemarkBakByIds(String[] ids);
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysImeiAutoLog;
|
||||
|
||||
/**
|
||||
* 自动模式日志Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-29
|
||||
*/
|
||||
public interface SysImeiAutoLogMapper extends BaseMapper<SysImeiAutoLog>
|
||||
{
|
||||
/**
|
||||
* 查询自动模式日志
|
||||
*
|
||||
* @param id 自动模式日志主键
|
||||
* @return 自动模式日志
|
||||
*/
|
||||
public SysImeiAutoLog selectSysImeiAutoLogById(Long id);
|
||||
|
||||
/**
|
||||
* 查询自动模式日志列表
|
||||
*
|
||||
* @param sysImeiAutoLog 自动模式日志
|
||||
* @return 自动模式日志集合
|
||||
*/
|
||||
public List<SysImeiAutoLog> selectSysImeiAutoLogList(SysImeiAutoLog sysImeiAutoLog);
|
||||
|
||||
/**
|
||||
* 新增自动模式日志
|
||||
*
|
||||
* @param sysImeiAutoLog 自动模式日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysImeiAutoLog(SysImeiAutoLog sysImeiAutoLog);
|
||||
|
||||
/**
|
||||
* 修改自动模式日志
|
||||
*
|
||||
* @param sysImeiAutoLog 自动模式日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysImeiAutoLog(SysImeiAutoLog sysImeiAutoLog);
|
||||
|
||||
/**
|
||||
* 删除自动模式日志
|
||||
*
|
||||
* @param id 自动模式日志主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysImeiAutoLogById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除自动模式日志
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysImeiAutoLogByIds(Long[] ids);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
|
||||
/**
|
||||
* 系统消息中心Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-26
|
||||
*/
|
||||
public interface SysMessageMapper extends BaseMapper<SysMessage>
|
||||
{
|
||||
/**
|
||||
* 查询系统消息中心
|
||||
*
|
||||
* @param id 系统消息中心主键
|
||||
* @return 系统消息中心
|
||||
*/
|
||||
public SysMessage selectSysMessageById(Long id);
|
||||
|
||||
/**
|
||||
* 查询系统消息中心列表
|
||||
*
|
||||
* @param sysMessage 系统消息中心
|
||||
* @return 系统消息中心集合
|
||||
*/
|
||||
public List<SysMessage> selectSysMessageList(SysMessage sysMessage);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 新增系统消息中心
|
||||
*
|
||||
* @param sysMessage 系统消息中心
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysMessage(SysMessage sysMessage);
|
||||
|
||||
/**
|
||||
* 修改系统消息中心
|
||||
*
|
||||
* @param sysMessage 系统消息中心
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysMessage(SysMessage sysMessage);
|
||||
|
||||
/**
|
||||
* 删除系统消息中心
|
||||
*
|
||||
* @param id 系统消息中心主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysMessageById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除系统消息中心
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysMessageByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 获取消息概览
|
||||
* @param sysMessage
|
||||
* @return
|
||||
*/
|
||||
List<SysMessage> getMsgOverview(SysMessage sysMessage);
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.agri.system.domain.SysRollerAir;
|
||||
|
||||
/**
|
||||
* 自动化卷膜风口大小设置Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-04
|
||||
*/
|
||||
public interface SysRollerAirMapper extends BaseMapper<SysRollerAir>
|
||||
{
|
||||
/**
|
||||
* 查询自动化卷膜风口大小设置
|
||||
*
|
||||
* @param id 自动化卷膜风口大小设置主键
|
||||
* @return 自动化卷膜风口大小设置
|
||||
*/
|
||||
public SysRollerAir selectSysRollerAirById(Long id);
|
||||
|
||||
/**
|
||||
* 查询自动化卷膜风口大小设置列表
|
||||
*
|
||||
* @param sysRollerAir 自动化卷膜风口大小设置
|
||||
* @return 自动化卷膜风口大小设置集合
|
||||
*/
|
||||
public List<SysRollerAir> selectSysRollerAirList(SysRollerAir sysRollerAir);
|
||||
|
||||
/**
|
||||
* 新增自动化卷膜风口大小设置
|
||||
*
|
||||
* @param sysRollerAir 自动化卷膜风口大小设置
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysRollerAir(SysRollerAir sysRollerAir);
|
||||
|
||||
/**
|
||||
* 修改自动化卷膜风口大小设置
|
||||
*
|
||||
* @param sysRollerAir 自动化卷膜风口大小设置
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysRollerAir(SysRollerAir sysRollerAir);
|
||||
|
||||
/**
|
||||
* 删除自动化卷膜风口大小设置
|
||||
*
|
||||
* @param id 自动化卷膜风口大小设置主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysRollerAirById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除自动化卷膜风口大小设置
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysRollerAirByIds(Long[] ids);
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import com.agri.system.domain.SysRollerParam;
|
||||
import com.agri.system.domain.vo.RollerTermVO;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 卷膜参数配置Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
public interface SysRollerParamMapper extends BaseMapper<SysRollerParam>
|
||||
{
|
||||
/**
|
||||
* 查询卷膜参数配置
|
||||
*
|
||||
* @param id 卷膜参数配置主键
|
||||
* @return 卷膜参数配置
|
||||
*/
|
||||
public SysRollerParam selectSysRollerParamById(String id);
|
||||
|
||||
/**
|
||||
* 查询卷膜参数配置列表
|
||||
*
|
||||
* @param sysRollerParam 卷膜参数配置
|
||||
* @return 卷膜参数配置集合
|
||||
*/
|
||||
public List<SysRollerParam> selectSysRollerParamList(SysRollerParam sysRollerParam);
|
||||
|
||||
/**
|
||||
* 新增卷膜参数配置
|
||||
*
|
||||
* @param sysRollerParam 卷膜参数配置
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysRollerParam(SysRollerParam sysRollerParam);
|
||||
|
||||
/**
|
||||
* 修改卷膜参数配置
|
||||
*
|
||||
* @param sysRollerParam 卷膜参数配置
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysRollerParam(SysRollerParam sysRollerParam);
|
||||
|
||||
/**
|
||||
* 删除卷膜参数配置
|
||||
*
|
||||
* @param id 卷膜参数配置主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysRollerParamById(String id);
|
||||
|
||||
/**
|
||||
* 批量删除卷膜参数配置
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysRollerParamByIds(String[] ids);
|
||||
|
||||
|
||||
List<RollerTermVO> getRollerTerms(@Param("imeiList") List<String> imeiList);
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
import com.agri.system.domain.SysUserAgri;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 大棚信息(用户-设备关联)Mapper接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-25
|
||||
*/
|
||||
public interface SysUserAgriMapper extends BaseMapper<SysUserAgri>
|
||||
{
|
||||
/**
|
||||
* 查询大棚信息(用户-设备关联)
|
||||
*
|
||||
* @param id 大棚信息(用户-设备关联)主键
|
||||
* @return 大棚信息(用户-设备关联)
|
||||
*/
|
||||
public SysUserAgri selectSysUserAgriById(Long id);
|
||||
|
||||
/**
|
||||
* 查询大棚信息(用户-设备关联)列表
|
||||
*
|
||||
* @param sysUserAgri 大棚信息(用户-设备关联)
|
||||
* @return 大棚信息(用户-设备关联)集合
|
||||
*/
|
||||
public List<SysUserAgri> selectSysUserAgriList(SysUserAgri sysUserAgri);
|
||||
|
||||
/**
|
||||
* 新增大棚信息(用户-设备关联)
|
||||
*
|
||||
* @param sysUserAgri 大棚信息(用户-设备关联)
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysUserAgri(SysUserAgri sysUserAgri);
|
||||
|
||||
/**
|
||||
* 修改大棚信息(用户-设备关联)
|
||||
*
|
||||
* @param sysUserAgri 大棚信息(用户-设备关联)
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysUserAgri(SysUserAgri sysUserAgri);
|
||||
|
||||
/**
|
||||
* 删除大棚信息(用户-设备关联)
|
||||
*
|
||||
* @param id 大棚信息(用户-设备关联)主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysUserAgriById(Long id);
|
||||
|
||||
/**
|
||||
* 批量删除大棚信息(用户-设备关联)
|
||||
*
|
||||
* @param ids 需要删除的数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysUserAgriByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 查看大棚下用户
|
||||
* @param sysUserAgri
|
||||
* @return
|
||||
*/
|
||||
List<SysUserAgri> findAgriUser(SysUserAgri sysUserAgri);
|
||||
|
||||
/**
|
||||
* 查询所有用户 以及关联大棚的用户 disbaled展示true
|
||||
* @param sysUserAgri
|
||||
* @return
|
||||
*/
|
||||
List<SysUserAgri> findAllUser(SysUserAgri sysUserAgri);
|
||||
|
||||
List<Map<String, Object>> getRecentShareUser(SysUserAgri sysUserAgri);
|
||||
}
|
||||
|
|
@ -1,18 +1,16 @@
|
|||
package com.agri.system.mapper;
|
||||
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.agri.common.core.domain.entity.SysUser;
|
||||
|
||||
/**
|
||||
* 用户表 数据层
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface SysUserMapper extends BaseMapper<SysUser>
|
||||
public interface SysUserMapper
|
||||
{
|
||||
/**
|
||||
* 根据条件分页查询用户列表
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface AgriService {
|
||||
|
||||
List<SysMessage> saveMessage(List<SysAgriInfo> offlineList);
|
||||
|
||||
List<String> queryAllGreenhouseImei(List<SysAgriInfo> agriInfos);
|
||||
|
||||
}
|
||||
|
|
@ -1,23 +1,20 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import com.agri.system.domain.SysAgriInfo;
|
||||
import com.agri.system.domain.vo.AgriAutoInfoVo;
|
||||
import com.agri.system.domain.vo.AgriInfoView;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 大棚管理Service接口
|
||||
*
|
||||
*
|
||||
* @author agri
|
||||
* @date 2026-01-08
|
||||
*/
|
||||
public interface ISysAgriInfoService extends IService<SysAgriInfo> {
|
||||
/**
|
||||
* 查询大棚管理
|
||||
*
|
||||
*
|
||||
* @param id 大棚管理主键
|
||||
* @return 大棚管理
|
||||
*/
|
||||
|
|
@ -25,7 +22,7 @@ public interface ISysAgriInfoService extends IService<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 查询大棚管理列表
|
||||
*
|
||||
*
|
||||
* @param sysAgriInfo 大棚管理
|
||||
* @return 大棚管理集合
|
||||
*/
|
||||
|
|
@ -33,7 +30,7 @@ public interface ISysAgriInfoService extends IService<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 新增大棚管理
|
||||
*
|
||||
*
|
||||
* @param sysAgriInfo 大棚管理
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -41,7 +38,7 @@ public interface ISysAgriInfoService extends IService<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 修改大棚管理
|
||||
*
|
||||
*
|
||||
* @param sysAgriInfo 大棚管理
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -49,7 +46,7 @@ public interface ISysAgriInfoService extends IService<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 批量删除大棚管理
|
||||
*
|
||||
*
|
||||
* @param ids 需要删除的大棚管理主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -57,27 +54,9 @@ public interface ISysAgriInfoService extends IService<SysAgriInfo> {
|
|||
|
||||
/**
|
||||
* 删除大棚管理信息
|
||||
*
|
||||
*
|
||||
* @param id 大棚管理主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAgriInfoById(Long id);
|
||||
|
||||
|
||||
public List<SysAgriInfo> findAgriByUser(SysAgriInfo sysAgriInfo);
|
||||
|
||||
public List<AgriInfoView> findAgriInfoByUser(SysAgriInfo sysAgriInfo);
|
||||
|
||||
Map<String,Object> addAgriFromMobile(SysAgriInfo sysAgriInfo);
|
||||
|
||||
List<AgriAutoInfoVo> findAgriOfAutoInfo();
|
||||
|
||||
|
||||
List<String> queryImeiByUserId(Long userId);
|
||||
|
||||
/**
|
||||
* 查询设备分享信息(可分享列表 + 分享给我的设备列表)
|
||||
* @return 设备分享信息
|
||||
*/
|
||||
Map<String, Object> selectShareInfoByUser(SysAgriInfo agriInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysAgriLimitBak;
|
||||
|
||||
/**
|
||||
* 大棚功能执行时间限位Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
public interface ISysAgriLimitBakService extends IService<SysAgriLimitBak> {
|
||||
/**
|
||||
* 查询大棚功能执行时间限位
|
||||
*
|
||||
* @param id 大棚功能执行时间限位主键
|
||||
* @return 大棚功能执行时间限位
|
||||
*/
|
||||
public SysAgriLimitBak selectSysAgriLimitBakById(String id);
|
||||
|
||||
/**
|
||||
* 查询大棚功能执行时间限位列表
|
||||
*
|
||||
* @param sysAgriLimitBak 大棚功能执行时间限位
|
||||
* @return 大棚功能执行时间限位集合
|
||||
*/
|
||||
public List<SysAgriLimitBak> selectSysAgriLimitBakList(SysAgriLimitBak sysAgriLimitBak);
|
||||
|
||||
/**
|
||||
* 新增大棚功能执行时间限位
|
||||
*
|
||||
* @param sysAgriLimitBak 大棚功能执行时间限位
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysAgriLimitBak(SysAgriLimitBak sysAgriLimitBak);
|
||||
|
||||
/**
|
||||
* 修改大棚功能执行时间限位
|
||||
*
|
||||
* @param sysAgriLimitBak 大棚功能执行时间限位
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysAgriLimitBak(SysAgriLimitBak sysAgriLimitBak);
|
||||
|
||||
/**
|
||||
* 批量删除大棚功能执行时间限位
|
||||
*
|
||||
* @param ids 需要删除的大棚功能执行时间限位主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAgriLimitBakByIds(String[] ids);
|
||||
|
||||
/**
|
||||
* 删除大棚功能执行时间限位信息
|
||||
*
|
||||
* @param id 大棚功能执行时间限位主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAgriLimitBakById(String id);
|
||||
|
||||
SysAgriLimitBak getAgriLimitByImei(String imei);
|
||||
|
||||
boolean saveAgriLimit(SysAgriLimitBak sysAgriLimitBak);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.agri.system.domain.vo.AgriTermVo;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysAutoTerm;
|
||||
|
||||
/**
|
||||
* 卷膜运行条件Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-02-27
|
||||
*/
|
||||
public interface ISysAutoTermService extends IService<SysAutoTerm> {
|
||||
/**
|
||||
* 查询卷膜运行条件
|
||||
*
|
||||
* @param id 卷膜运行条件主键
|
||||
* @return 卷膜运行条件
|
||||
*/
|
||||
public SysAutoTerm selectSysAutoTermById(String id);
|
||||
|
||||
/**
|
||||
* 查询卷膜运行条件列表
|
||||
*
|
||||
* @param sysAutoTerm 卷膜运行条件
|
||||
* @return 卷膜运行条件集合
|
||||
*/
|
||||
public List<SysAutoTerm> selectSysAutoTermList(SysAutoTerm sysAutoTerm);
|
||||
|
||||
/**
|
||||
* 新增卷膜运行条件
|
||||
*
|
||||
* @param sysAutoTerm 卷膜运行条件
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysAutoTerm(SysAutoTerm sysAutoTerm);
|
||||
|
||||
/**
|
||||
* 修改卷膜运行条件
|
||||
*
|
||||
* @param sysAutoTerm 卷膜运行条件
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysAutoTerm(SysAutoTerm sysAutoTerm);
|
||||
|
||||
/**
|
||||
* 批量删除卷膜运行条件
|
||||
*
|
||||
* @param ids 需要删除的卷膜运行条件主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAutoTermByIds(String[] ids);
|
||||
|
||||
/**
|
||||
* 删除卷膜运行条件信息
|
||||
*
|
||||
* @param id 卷膜运行条件主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysAutoTermById(String id);
|
||||
|
||||
|
||||
|
||||
boolean saveAgriTerm(List<AgriTermVo> agriTerms);
|
||||
|
||||
String validate(List<AgriTermVo> agriTerms);
|
||||
|
||||
List<AgriTermVo> getAgriTerm(String imei);
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysDevOperLog;
|
||||
|
||||
/**
|
||||
* 设备控制操作日志Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
public interface ISysDevOperLogService extends IService<SysDevOperLog> {
|
||||
/**
|
||||
* 查询设备控制操作日志
|
||||
*
|
||||
* @param id 设备控制操作日志主键
|
||||
* @return 设备控制操作日志
|
||||
*/
|
||||
public SysDevOperLog selectSysDevOperLogById(Long id);
|
||||
|
||||
/**
|
||||
* 查询设备控制操作日志列表
|
||||
*
|
||||
* @param sysDevOperLog 设备控制操作日志
|
||||
* @return 设备控制操作日志集合
|
||||
*/
|
||||
public List<SysDevOperLog> selectSysDevOperLogList(SysDevOperLog sysDevOperLog);
|
||||
|
||||
/**
|
||||
* 新增设备控制操作日志
|
||||
*
|
||||
* @param sysDevOperLog 设备控制操作日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysDevOperLog(SysDevOperLog sysDevOperLog);
|
||||
|
||||
/**
|
||||
* 修改设备控制操作日志
|
||||
*
|
||||
* @param sysDevOperLog 设备控制操作日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysDevOperLog(SysDevOperLog sysDevOperLog);
|
||||
|
||||
/**
|
||||
* 批量删除设备控制操作日志
|
||||
*
|
||||
* @param ids 需要删除的设备控制操作日志主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDevOperLogByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除设备控制操作日志信息
|
||||
*
|
||||
* @param id 设备控制操作日志主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDevOperLogById(Long id);
|
||||
|
||||
|
||||
Map<String, Map<String, Integer>> getTodayLogCountByImeiMap(List<String> imeiList);
|
||||
}
|
||||
|
|
@ -1,24 +1,19 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import com.agri.system.domain.SysDtuData;
|
||||
import com.agri.system.domain.vo.UChartsDataView;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.agri.system.domain.SysDtuData;
|
||||
|
||||
/**
|
||||
* DTU温湿度上报数据Service接口
|
||||
*
|
||||
*
|
||||
* @author agri
|
||||
* @date 2025-12-23
|
||||
*/
|
||||
public interface ISysDtuDataService extends IService<SysDtuData>
|
||||
public interface ISysDtuDataService
|
||||
{
|
||||
/**
|
||||
* 查询DTU温湿度上报数据
|
||||
*
|
||||
*
|
||||
* @param id DTU温湿度上报数据主键
|
||||
* @return DTU温湿度上报数据
|
||||
*/
|
||||
|
|
@ -26,7 +21,7 @@ public interface ISysDtuDataService extends IService<SysDtuData>
|
|||
|
||||
/**
|
||||
* 查询DTU温湿度上报数据列表
|
||||
*
|
||||
*
|
||||
* @param sysDtuData DTU温湿度上报数据
|
||||
* @return DTU温湿度上报数据集合
|
||||
*/
|
||||
|
|
@ -41,7 +36,7 @@ public interface ISysDtuDataService extends IService<SysDtuData>
|
|||
|
||||
/**
|
||||
* 新增DTU温湿度上报数据
|
||||
*
|
||||
*
|
||||
* @param sysDtuData DTU温湿度上报数据
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -49,7 +44,7 @@ public interface ISysDtuDataService extends IService<SysDtuData>
|
|||
|
||||
/**
|
||||
* 修改DTU温湿度上报数据
|
||||
*
|
||||
*
|
||||
* @param sysDtuData DTU温湿度上报数据
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -57,7 +52,7 @@ public interface ISysDtuDataService extends IService<SysDtuData>
|
|||
|
||||
/**
|
||||
* 批量删除DTU温湿度上报数据
|
||||
*
|
||||
*
|
||||
* @param ids 需要删除的DTU温湿度上报数据主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
|
|
@ -65,15 +60,9 @@ public interface ISysDtuDataService extends IService<SysDtuData>
|
|||
|
||||
/**
|
||||
* 删除DTU温湿度上报数据信息
|
||||
*
|
||||
*
|
||||
* @param id DTU温湿度上报数据主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDtuDataById(Long id);
|
||||
|
||||
List<Map<String, Object>> getLastDtuDataByImeiList(List<String> imeiList);
|
||||
|
||||
UChartsDataView getHistoryData(String imei, LocalDateTime startTime, LocalDateTime endTime);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.agri.common.core.domain.AjaxResult;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysDtuRemarkBak;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* dtu设备备注Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-17
|
||||
*/
|
||||
public interface ISysDtuRemarkBakService extends IService<SysDtuRemarkBak> {
|
||||
/**
|
||||
* 查询dtu设备备注
|
||||
*
|
||||
* @param id dtu设备备注主键
|
||||
* @return dtu设备备注
|
||||
*/
|
||||
public SysDtuRemarkBak selectSysDtuRemarkBakById(String id);
|
||||
|
||||
/**
|
||||
* 查询dtu设备备注列表
|
||||
*
|
||||
* @param sysDtuRemarkBak dtu设备备注
|
||||
* @return dtu设备备注集合
|
||||
*/
|
||||
public List<SysDtuRemarkBak> selectSysDtuRemarkBakList(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
|
||||
/**
|
||||
* 新增dtu设备备注
|
||||
*
|
||||
* @param sysDtuRemarkBak dtu设备备注
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysDtuRemarkBak(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
|
||||
/**
|
||||
* 修改dtu设备备注
|
||||
*
|
||||
* @param sysDtuRemarkBak dtu设备备注
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysDtuRemarkBak(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
|
||||
/**
|
||||
* 批量删除dtu设备备注
|
||||
*
|
||||
* @param ids 需要删除的dtu设备备注主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDtuRemarkBakByIds(String[] ids);
|
||||
|
||||
/**
|
||||
* 删除dtu设备备注信息
|
||||
*
|
||||
* @param id dtu设备备注主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysDtuRemarkBakById(String id);
|
||||
|
||||
|
||||
SysDtuRemarkBak getDtuRemarkByImei(String imei);
|
||||
|
||||
|
||||
boolean saveAgriRemark(SysDtuRemarkBak sysDtuRemarkBak);
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysImeiAutoLog;
|
||||
|
||||
/**
|
||||
* 自动模式日志Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-29
|
||||
*/
|
||||
public interface ISysImeiAutoLogService extends IService<SysImeiAutoLog> {
|
||||
/**
|
||||
* 查询自动模式日志
|
||||
*
|
||||
* @param id 自动模式日志主键
|
||||
* @return 自动模式日志
|
||||
*/
|
||||
public SysImeiAutoLog selectSysImeiAutoLogById(Long id);
|
||||
|
||||
/**
|
||||
* 查询自动模式日志列表
|
||||
*
|
||||
* @param sysImeiAutoLog 自动模式日志
|
||||
* @return 自动模式日志集合
|
||||
*/
|
||||
public List<SysImeiAutoLog> selectSysImeiAutoLogList(SysImeiAutoLog sysImeiAutoLog);
|
||||
|
||||
/**
|
||||
* 新增自动模式日志
|
||||
*
|
||||
* @param sysImeiAutoLog 自动模式日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysImeiAutoLog(SysImeiAutoLog sysImeiAutoLog);
|
||||
|
||||
/**
|
||||
* 修改自动模式日志
|
||||
*
|
||||
* @param sysImeiAutoLog 自动模式日志
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysImeiAutoLog(SysImeiAutoLog sysImeiAutoLog);
|
||||
|
||||
/**
|
||||
* 批量删除自动模式日志
|
||||
*
|
||||
* @param ids 需要删除的自动模式日志主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysImeiAutoLogByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除自动模式日志信息
|
||||
*
|
||||
* @param id 自动模式日志主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysImeiAutoLogById(Long id);
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysMessage;
|
||||
|
||||
/**
|
||||
* 系统消息中心Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-26
|
||||
*/
|
||||
public interface ISysMessageService extends IService<SysMessage> {
|
||||
/**
|
||||
* 查询系统消息中心
|
||||
*
|
||||
* @param id 系统消息中心主键
|
||||
* @return 系统消息中心
|
||||
*/
|
||||
public SysMessage selectSysMessageById(Long id);
|
||||
|
||||
/**
|
||||
* 查询系统消息中心列表
|
||||
*
|
||||
* @param sysMessage 系统消息中心
|
||||
* @return 系统消息中心集合
|
||||
*/
|
||||
public List<SysMessage> selectSysMessageList(SysMessage sysMessage);
|
||||
|
||||
/**
|
||||
* 新增系统消息中心
|
||||
*
|
||||
* @param sysMessage 系统消息中心
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysMessage(SysMessage sysMessage);
|
||||
|
||||
/**
|
||||
* 修改系统消息中心
|
||||
*
|
||||
* @param sysMessage 系统消息中心
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysMessage(SysMessage sysMessage);
|
||||
|
||||
/**
|
||||
* 批量删除系统消息中心
|
||||
*
|
||||
* @param ids 需要删除的系统消息中心主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysMessageByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除系统消息中心信息
|
||||
*
|
||||
* @param id 系统消息中心主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysMessageById(Long id);
|
||||
|
||||
List<SysMessage> getMsgOverview(SysMessage sysMessage);
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package com.agri.system.service;
|
||||
|
||||
import java.util.List;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.agri.system.domain.SysRollerAir;
|
||||
|
||||
/**
|
||||
* 自动化卷膜风口大小设置Service接口
|
||||
*
|
||||
* @author lld
|
||||
* @date 2026-03-04
|
||||
*/
|
||||
public interface ISysRollerAirService extends IService<SysRollerAir> {
|
||||
/**
|
||||
* 查询自动化卷膜风口大小设置
|
||||
*
|
||||
* @param id 自动化卷膜风口大小设置主键
|
||||
* @return 自动化卷膜风口大小设置
|
||||
*/
|
||||
public SysRollerAir selectSysRollerAirById(Long id);
|
||||
|
||||
/**
|
||||
* 查询自动化卷膜风口大小设置列表
|
||||
*
|
||||
* @param sysRollerAir 自动化卷膜风口大小设置
|
||||
* @return 自动化卷膜风口大小设置集合
|
||||
*/
|
||||
public List<SysRollerAir> selectSysRollerAirList(SysRollerAir sysRollerAir);
|
||||
|
||||
/**
|
||||
* 新增自动化卷膜风口大小设置
|
||||
*
|
||||
* @param sysRollerAir 自动化卷膜风口大小设置
|
||||
* @return 结果
|
||||
*/
|
||||
public int insertSysRollerAir(SysRollerAir sysRollerAir);
|
||||
|
||||
/**
|
||||
* 修改自动化卷膜风口大小设置
|
||||
*
|
||||
* @param sysRollerAir 自动化卷膜风口大小设置
|
||||
* @return 结果
|
||||
*/
|
||||
public int updateSysRollerAir(SysRollerAir sysRollerAir);
|
||||
|
||||
/**
|
||||
* 批量删除自动化卷膜风口大小设置
|
||||
*
|
||||
* @param ids 需要删除的自动化卷膜风口大小设置主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysRollerAirByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
* 删除自动化卷膜风口大小设置信息
|
||||
*
|
||||
* @param id 自动化卷膜风口大小设置主键
|
||||
* @return 结果
|
||||
*/
|
||||
public int deleteSysRollerAirById(Long id);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue