Commit eb7269083ab691f49ccbb81b513c0a344d8125c7

Authored by YunaiV
2 parents d597d005 638976da

Merge branch 'feature/iot' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

Showing 340 changed files with 18037 additions and 1854 deletions

Too many changes.

To preserve performance only 100 of 340 files are displayed.

.gitignore
@@ -51,3 +51,4 @@ rebel.xml @@ -51,3 +51,4 @@ rebel.xml
51 application-my.yaml 51 application-my.yaml
52 52
53 /yudao-ui-app/unpackage/ 53 /yudao-ui-app/unpackage/
  54 +**/.DS_Store
@@ -16,7 +16,7 @@ @@ -16,7 +16,7 @@
16 <module>yudao-module-system</module> 16 <module>yudao-module-system</module>
17 <module>yudao-module-infra</module> 17 <module>yudao-module-infra</module>
18 <!-- <module>yudao-module-member</module>--> 18 <!-- <module>yudao-module-member</module>-->
19 -<!-- <module>yudao-module-bpm</module>--> 19 + <module>yudao-module-bpm</module>
20 <!-- <module>yudao-module-report</module>--> 20 <!-- <module>yudao-module-report</module>-->
21 <!-- <module>yudao-module-mp</module>--> 21 <!-- <module>yudao-module-mp</module>-->
22 <!-- <module>yudao-module-pay</module>--> 22 <!-- <module>yudao-module-pay</module>-->
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 <!-- <module>yudao-module-crm</module>--> 24 <!-- <module>yudao-module-crm</module>-->
25 <!-- <module>yudao-module-erp</module>--> 25 <!-- <module>yudao-module-erp</module>-->
26 <!-- <module>yudao-module-ai</module>--> 26 <!-- <module>yudao-module-ai</module>-->
27 -<!-- <module>yudao-module-iot</module>--> 27 + <module>yudao-module-iot</module>
28 </modules> 28 </modules>
29 29
30 <name>${project.artifactId}</name> 30 <name>${project.artifactId}</name>
yudao-dependencies/pom.xml
@@ -32,8 +32,9 @@ @@ -32,8 +32,9 @@
32 <dm8.jdbc.version>8.1.3.140</dm8.jdbc.version> 32 <dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
33 <kingbase.jdbc.version>8.6.0</kingbase.jdbc.version> 33 <kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
34 <opengauss.jdbc.version>5.1.0</opengauss.jdbc.version> 34 <opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
  35 + <taos.version>3.3.3</taos.version>
35 <!-- 消息队列 --> 36 <!-- 消息队列 -->
36 - <rocketmq-spring.version>2.3.1</rocketmq-spring.version> 37 + <rocketmq-spring.version>2.3.2</rocketmq-spring.version>
37 <!-- 服务保障相关 --> 38 <!-- 服务保障相关 -->
38 <lock4j.version>2.2.7</lock4j.version> 39 <lock4j.version>2.2.7</lock4j.version>
39 <!-- 监控相关 --> 40 <!-- 监控相关 -->
@@ -65,6 +66,8 @@ @@ -65,6 +66,8 @@
65 <bizlog-sdk.version>3.0.6</bizlog-sdk.version> 66 <bizlog-sdk.version>3.0.6</bizlog-sdk.version>
66 <netty.version>4.1.116.Final</netty.version> 67 <netty.version>4.1.116.Final</netty.version>
67 <mqtt.version>1.2.5</mqtt.version> 68 <mqtt.version>1.2.5</mqtt.version>
  69 + <pf4j-spring.version>0.9.0</pf4j-spring.version>
  70 + <vertx.version>4.5.13</vertx.version>
68 <!-- 三方云服务相关 --> 71 <!-- 三方云服务相关 -->
69 <commons-io.version>2.17.0</commons-io.version> 72 <commons-io.version>2.17.0</commons-io.version>
70 <commons-compress.version>1.27.1</commons-compress.version> 73 <commons-compress.version>1.27.1</commons-compress.version>
@@ -263,6 +266,12 @@ @@ -263,6 +266,12 @@
263 <version>${kingbase.jdbc.version}</version> 266 <version>${kingbase.jdbc.version}</version>
264 </dependency> 267 </dependency>
265 268
  269 + <dependency>
  270 + <groupId>com.taosdata.jdbc</groupId>
  271 + <artifactId>taos-jdbcdriver</artifactId>
  272 + <version>${taos.version}</version>
  273 + </dependency>
  274 +
266 <!-- Job 定时任务相关 --> 275 <!-- Job 定时任务相关 -->
267 <dependency> 276 <dependency>
268 <groupId>cn.iocoder.boot</groupId> 277 <groupId>cn.iocoder.boot</groupId>
@@ -276,7 +285,6 @@ @@ -276,7 +285,6 @@
276 <artifactId>yudao-spring-boot-starter-mq</artifactId> 285 <artifactId>yudao-spring-boot-starter-mq</artifactId>
277 <version>${revision}</version> 286 <version>${revision}</version>
278 </dependency> 287 </dependency>
279 -  
280 <dependency> 288 <dependency>
281 <groupId>org.apache.rocketmq</groupId> 289 <groupId>org.apache.rocketmq</groupId>
282 <artifactId>rocketmq-spring-boot-starter</artifactId> 290 <artifactId>rocketmq-spring-boot-starter</artifactId>
@@ -591,6 +599,36 @@ @@ -591,6 +599,36 @@
591 </exclusions> 599 </exclusions>
592 </dependency> 600 </dependency>
593 601
  602 + <!-- PF4J -->
  603 + <dependency>
  604 + <groupId>org.pf4j</groupId>
  605 + <artifactId>pf4j-spring</artifactId>
  606 + <version>${pf4j-spring.version}</version>
  607 + <exclusions>
  608 + <exclusion>
  609 + <groupId>org.slf4j</groupId>
  610 + <artifactId>slf4j-log4j12</artifactId>
  611 + </exclusion>
  612 + </exclusions>
  613 + </dependency>
  614 +
  615 + <!-- Vert.x -->
  616 + <dependency>
  617 + <groupId>io.vertx</groupId>
  618 + <artifactId>vertx-core</artifactId>
  619 + <version>${vertx.version}</version>
  620 + </dependency>
  621 + <dependency>
  622 + <groupId>io.vertx</groupId>
  623 + <artifactId>vertx-web</artifactId>
  624 + <version>${vertx.version}</version>
  625 + </dependency>
  626 + <dependency>
  627 + <groupId>io.vertx</groupId>
  628 + <artifactId>vertx-mqtt</artifactId>
  629 + <version>${vertx.version}</version>
  630 + </dependency>
  631 +
594 <!-- MQTT --> 632 <!-- MQTT -->
595 <dependency> 633 <dependency>
596 <groupId>org.eclipse.paho</groupId> 634 <groupId>org.eclipse.paho</groupId>
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/RpcConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.common.enums;
  2 +
  3 +/**
  4 + * RPC 相关的枚举
  5 + *
  6 + * 虽然放在 yudao-spring-boot-starter-rpc 会相对合适,但是每个 API 模块需要使用到,所以暂时只好放在此处
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public class RpcConstants {
  11 +
  12 + /**
  13 + * RPC API 的前缀
  14 + */
  15 + public static final String RPC_API_PREFIX = "/rpc-api";
  16 +
  17 +}
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java
@@ -7,13 +7,15 @@ import cn.hutool.core.util.ReflectUtil; @@ -7,13 +7,15 @@ import cn.hutool.core.util.ReflectUtil;
7 import cn.hutool.core.util.StrUtil; 7 import cn.hutool.core.util.StrUtil;
8 import cn.hutool.http.HttpRequest; 8 import cn.hutool.http.HttpRequest;
9 import cn.hutool.http.HttpResponse; 9 import cn.hutool.http.HttpResponse;
  10 +import jakarta.servlet.http.HttpServletRequest;
10 import org.springframework.util.StringUtils; 11 import org.springframework.util.StringUtils;
11 import org.springframework.web.util.UriComponents; 12 import org.springframework.web.util.UriComponents;
12 import org.springframework.web.util.UriComponentsBuilder; 13 import org.springframework.web.util.UriComponentsBuilder;
13 14
14 -import jakarta.servlet.http.HttpServletRequest;  
15 import java.net.URI; 15 import java.net.URI;
  16 +import java.net.URLEncoder;
16 import java.nio.charset.Charset; 17 import java.nio.charset.Charset;
  18 +import java.nio.charset.StandardCharsets;
17 import java.util.Map; 19 import java.util.Map;
18 20
19 /** 21 /**
@@ -23,6 +25,16 @@ import java.util.Map; @@ -23,6 +25,16 @@ import java.util.Map;
23 */ 25 */
24 public class HttpUtils { 26 public class HttpUtils {
25 27
  28 + /**
  29 + * 编码 URL 参数
  30 + *
  31 + * @param value 参数
  32 + * @return 编码后的参数
  33 + */
  34 + public static String encodeUtf8(String value) {
  35 + return URLEncoder.encode(value, StandardCharsets.UTF_8);
  36 + }
  37 +
26 @SuppressWarnings("unchecked") 38 @SuppressWarnings("unchecked")
27 public static String replaceUrlQuery(String url, String key, String value) { 39 public static String replaceUrlQuery(String url, String key, String value) {
28 UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset()); 40 UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/NumberUtils.java
1 package cn.iocoder.yudao.framework.common.util.number; 1 package cn.iocoder.yudao.framework.common.util.number;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.util.NumberUtil; 4 import cn.hutool.core.util.NumberUtil;
4 import cn.hutool.core.util.StrUtil; 5 import cn.hutool.core.util.StrUtil;
5 6
6 import java.math.BigDecimal; 7 import java.math.BigDecimal;
  8 +import java.util.List;
7 9
8 /** 10 /**
9 * 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能 11 * 数字的工具类,补全 {@link cn.hutool.core.util.NumberUtil} 的功能
@@ -20,6 +22,18 @@ public class NumberUtils { @@ -20,6 +22,18 @@ public class NumberUtils {
20 return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null; 22 return StrUtil.isNotEmpty(str) ? Integer.valueOf(str) : null;
21 } 23 }
22 24
  25 + public static boolean isAllNumber(List<String> values) {
  26 + if (CollUtil.isEmpty(values)) {
  27 + return false;
  28 + }
  29 + for (String value : values) {
  30 + if (!NumberUtil.isNumber(value)) {
  31 + return false;
  32 + }
  33 + }
  34 + return true;
  35 + }
  36 +
23 /** 37 /**
24 * 通过经纬度获取地球上两点之间的距离 38 * 通过经纬度获取地球上两点之间的距离
25 * 39 *
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java
@@ -98,4 +98,8 @@ public class ServletUtils { @@ -98,4 +98,8 @@ public class ServletUtils {
98 return JakartaServletUtil.getParamMap(request); 98 return JakartaServletUtil.getParamMap(request);
99 } 99 }
100 100
  101 + public static Map<String, String> getHeaderMap(HttpServletRequest request) {
  102 + return JakartaServletUtil.getHeaderMap(request);
  103 + }
  104 +
101 } 105 }
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/spring/SpringExpressionUtils.java
@@ -97,12 +97,26 @@ public class SpringExpressionUtils { @@ -97,12 +97,26 @@ public class SpringExpressionUtils {
97 * @return 执行界面 97 * @return 执行界面
98 */ 98 */
99 public static Object parseExpression(String expressionString) { 99 public static Object parseExpression(String expressionString) {
  100 + return parseExpression(expressionString, null);
  101 + }
  102 +
  103 + /**
  104 + * 从 Bean 工厂,解析 EL 表达式的结果
  105 + *
  106 + * @param expressionString EL 表达式
  107 + * @param variables 变量
  108 + * @return 执行界面
  109 + */
  110 + public static Object parseExpression(String expressionString, Map<String, Object> variables) {
100 if (StrUtil.isBlank(expressionString)) { 111 if (StrUtil.isBlank(expressionString)) {
101 return null; 112 return null;
102 } 113 }
103 Expression expression = EXPRESSION_PARSER.parseExpression(expressionString); 114 Expression expression = EXPRESSION_PARSER.parseExpression(expressionString);
104 StandardEvaluationContext context = new StandardEvaluationContext(); 115 StandardEvaluationContext context = new StandardEvaluationContext();
105 context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getApplicationContext())); 116 context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getApplicationContext()));
  117 + if (MapUtil.isNotEmpty(variables)) {
  118 + context.setVariables(variables);
  119 + }
106 return expression.getValue(context); 120 return expression.getValue(context);
107 } 121 }
108 122
yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/util/TenantUtils.java
@@ -45,6 +45,7 @@ public class TenantUtils { @@ -45,6 +45,7 @@ public class TenantUtils {
45 * 45 *
46 * @param tenantId 租户编号 46 * @param tenantId 租户编号
47 * @param callable 逻辑 47 * @param callable 逻辑
  48 + * @return 结果
48 */ 49 */
49 public static <V> V execute(Long tenantId, Callable<V> callable) { 50 public static <V> V execute(Long tenantId, Callable<V> callable) {
50 Long oldTenantId = TenantContextHolder.getTenantId(); 51 Long oldTenantId = TenantContextHolder.getTenantId();
@@ -79,6 +80,25 @@ public class TenantUtils { @@ -79,6 +80,25 @@ public class TenantUtils {
79 } 80 }
80 81
81 /** 82 /**
  83 + * 忽略租户,执行对应的逻辑
  84 + *
  85 + * @param callable 逻辑
  86 + * @return 结果
  87 + */
  88 + public static <V> V executeIgnore(Callable<V> callable) {
  89 + Boolean oldIgnore = TenantContextHolder.isIgnore();
  90 + try {
  91 + TenantContextHolder.setIgnore(true);
  92 + // 执行逻辑
  93 + return callable.call();
  94 + } catch (Exception e) {
  95 + throw new RuntimeException(e);
  96 + } finally {
  97 + TenantContextHolder.setIgnore(oldIgnore);
  98 + }
  99 + }
  100 +
  101 + /**
82 * 将多租户编号,添加到 header 中 102 * 将多租户编号,添加到 header 中
83 * 103 *
84 * @param headers HTTP 请求 headers 104 * @param headers HTTP 请求 headers
yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/util/ExcelUtils.java
1 package cn.iocoder.yudao.framework.excel.core.util; 1 package cn.iocoder.yudao.framework.excel.core.util;
2 2
  3 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
3 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler; 4 import cn.iocoder.yudao.framework.excel.core.handler.SelectSheetWriteHandler;
4 import com.alibaba.excel.EasyExcel; 5 import com.alibaba.excel.EasyExcel;
5 import com.alibaba.excel.converters.longconverter.LongStringConverter; 6 import com.alibaba.excel.converters.longconverter.LongStringConverter;
@@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse; @@ -8,8 +9,6 @@ import jakarta.servlet.http.HttpServletResponse;
8 import org.springframework.web.multipart.MultipartFile; 9 import org.springframework.web.multipart.MultipartFile;
9 10
10 import java.io.IOException; 11 import java.io.IOException;
11 -import java.net.URLEncoder;  
12 -import java.nio.charset.StandardCharsets;  
13 import java.util.List; 12 import java.util.List;
14 13
15 /** 14 /**
@@ -40,7 +39,7 @@ public class ExcelUtils { @@ -40,7 +39,7 @@ public class ExcelUtils {
40 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 39 .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
41 .sheet(sheetName).doWrite(data); 40 .sheet(sheetName).doWrite(data);
42 // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 41 // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了
43 - response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name())); 42 + response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
44 response.setContentType("application/vnd.ms-excel;charset=UTF-8"); 43 response.setContentType("application/vnd.ms-excel;charset=UTF-8");
45 } 44 }
46 45
yudao-framework/yudao-spring-boot-starter-mybatis/pom.xml
@@ -63,6 +63,11 @@ @@ -63,6 +63,11 @@
63 <artifactId>opengauss-jdbc</artifactId> 63 <artifactId>opengauss-jdbc</artifactId>
64 <optional>true</optional> 64 <optional>true</optional>
65 </dependency> 65 </dependency>
  66 + <dependency>
  67 + <groupId>com.taosdata.jdbc</groupId>
  68 + <artifactId>taos-jdbcdriver</artifactId>
  69 + <optional>true</optional>
  70 + </dependency>
66 71
67 <dependency> 72 <dependency>
68 <groupId>com.alibaba</groupId> 73 <groupId>com.alibaba</groupId>
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/type/LongSetTypeHandler.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.mybatis.core.type;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.string.StrUtils;
  5 +import org.apache.ibatis.type.JdbcType;
  6 +import org.apache.ibatis.type.MappedJdbcTypes;
  7 +import org.apache.ibatis.type.MappedTypes;
  8 +import org.apache.ibatis.type.TypeHandler;
  9 +
  10 +import java.sql.CallableStatement;
  11 +import java.sql.PreparedStatement;
  12 +import java.sql.ResultSet;
  13 +import java.sql.SQLException;
  14 +import java.util.List;
  15 +import java.util.Set;
  16 +
  17 +/**
  18 + * Set<Long> 的类型转换器实现类,对应数据库的 varchar 类型
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@MappedJdbcTypes(JdbcType.VARCHAR)
  23 +@MappedTypes(List.class)
  24 +public class LongSetTypeHandler implements TypeHandler<Set<Long>> {
  25 +
  26 + private static final String COMMA = ",";
  27 +
  28 + @Override
  29 + public void setParameter(PreparedStatement ps, int i, Set<Long> strings, JdbcType jdbcType) throws SQLException {
  30 + // 设置占位符
  31 + ps.setString(i, CollUtil.join(strings, COMMA));
  32 + }
  33 +
  34 + @Override
  35 + public Set<Long> getResult(ResultSet rs, String columnName) throws SQLException {
  36 + String value = rs.getString(columnName);
  37 + return getResult(value);
  38 + }
  39 +
  40 + @Override
  41 + public Set<Long> getResult(ResultSet rs, int columnIndex) throws SQLException {
  42 + String value = rs.getString(columnIndex);
  43 + return getResult(value);
  44 + }
  45 +
  46 + @Override
  47 + public Set<Long> getResult(CallableStatement cs, int columnIndex) throws SQLException {
  48 + String value = cs.getString(columnIndex);
  49 + return getResult(value);
  50 + }
  51 +
  52 + private Set<Long> getResult(String value) {
  53 + if (value == null) {
  54 + return null;
  55 + }
  56 + return StrUtils.splitToLongSet(value, COMMA);
  57 + }
  58 +}
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
@@ -62,9 +62,9 @@ public class BannerApplicationRunner implements ApplicationRunner { @@ -62,9 +62,9 @@ public class BannerApplicationRunner implements ApplicationRunner {
62 if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) { 62 if (isNotPresent("cn.iocoder.yudao.module.ai.framework.web.config.AiWebConfiguration")) {
63 System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]"); 63 System.out.println("[AI 大模型 yudao-module-ai - 已禁用][参考 https://doc.iocoder.cn/ai/build/ 开启]");
64 } 64 }
65 - // IOT 物联网 65 + // IoT 物联网
66 if (isNotPresent("cn.iocoder.yudao.module.iot.framework.web.config.IotWebConfiguration")) { 66 if (isNotPresent("cn.iocoder.yudao.module.iot.framework.web.config.IotWebConfiguration")) {
67 - System.out.println("[IOT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]"); 67 + System.out.println("[IoT 物联网 yudao-module-iot - 已禁用][参考 https://doc.iocoder.cn/iot/build/ 开启]");
68 } 68 }
69 }); 69 });
70 } 70 }
yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -395,11 +395,11 @@ public class GlobalExceptionHandler { @@ -395,11 +395,11 @@ public class GlobalExceptionHandler {
395 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 395 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
396 "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]"); 396 "[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
397 } 397 }
398 - // 9. IOT 物联网 398 + // 9. IoT 物联网
399 if (message.contains("iot_")) { 399 if (message.contains("iot_")) {
400 - log.error("[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); 400 + log.error("[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
401 return CommonResult.error(NOT_IMPLEMENTED.getCode(), 401 return CommonResult.error(NOT_IMPLEMENTED.getCode(),
402 - "[IOT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]"); 402 + "[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
403 } 403 }
404 return null; 404 return null;
405 } 405 }
yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/dal/dataobject/receivable/CrmReceivableDO.java
@@ -66,7 +66,9 @@ public class CrmReceivableDO extends BaseDO { @@ -66,7 +66,9 @@ public class CrmReceivableDO extends BaseDO {
66 */ 66 */
67 private LocalDateTime returnTime; 67 private LocalDateTime returnTime;
68 /** 68 /**
69 - * 回款方式,关联枚举{@link CrmReceivableReturnTypeEnum} 69 + * 回款方式
  70 + *
  71 + * 枚举 {@link CrmReceivableReturnTypeEnum}
70 */ 72 */
71 private Integer returnType; 73 private Integer returnType;
72 /** 74 /**
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/utils/FileTypeUtils.java
@@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils; @@ -2,13 +2,13 @@ package cn.iocoder.yudao.module.infra.framework.file.core.utils;
2 2
3 import cn.hutool.core.io.IoUtil; 3 import cn.hutool.core.io.IoUtil;
4 import cn.hutool.core.util.StrUtil; 4 import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
5 import com.alibaba.ttl.TransmittableThreadLocal; 6 import com.alibaba.ttl.TransmittableThreadLocal;
6 import jakarta.servlet.http.HttpServletResponse; 7 import jakarta.servlet.http.HttpServletResponse;
7 import lombok.SneakyThrows; 8 import lombok.SneakyThrows;
8 import org.apache.tika.Tika; 9 import org.apache.tika.Tika;
9 10
10 import java.io.IOException; 11 import java.io.IOException;
11 -import java.net.URLEncoder;  
12 12
13 /** 13 /**
14 * 文件类型 Utils 14 * 文件类型 Utils
@@ -60,7 +60,7 @@ public class FileTypeUtils { @@ -60,7 +60,7 @@ public class FileTypeUtils {
60 */ 60 */
61 public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException { 61 public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
62 // 设置 header 和 contentType 62 // 设置 header 和 contentType
63 - response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8")); 63 + response.setHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename));
64 String contentType = getMineType(content, filename); 64 String contentType = getMineType(content, filename);
65 response.setContentType(contentType); 65 response.setContentType(contentType);
66 // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题 66 // 针对 video 的特殊处理,解决视频地址在移动端播放的兼容性问题
yudao-module-iot/pom.xml
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 <modules> 10 <modules>
11 <module>yudao-module-iot-api</module> 11 <module>yudao-module-iot-api</module>
12 <module>yudao-module-iot-biz</module> 12 <module>yudao-module-iot-biz</module>
  13 + <module>yudao-module-iot-plugins</module>
13 </modules> 14 </modules>
14 <modelVersion>4.0.0</modelVersion> 15 <modelVersion>4.0.0</modelVersion>
15 16
yudao-module-iot/yudao-module-iot-api/pom.xml
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 <packaging>jar</packaging> 12 <packaging>jar</packaging>
13 13
14 <name>${project.artifactId}</name> 14 <name>${project.artifactId}</name>
  15 + <!-- TODO 芋艿:需要在整理下,特别是 PF4J -->
15 <description> 16 <description>
16 物联网 模块 API,暴露给其它模块调用 17 物联网 模块 API,暴露给其它模块调用
17 </description> 18 </description>
@@ -21,6 +22,32 @@ @@ -21,6 +22,32 @@
21 <groupId>cn.iocoder.boot</groupId> 22 <groupId>cn.iocoder.boot</groupId>
22 <artifactId>yudao-common</artifactId> 23 <artifactId>yudao-common</artifactId>
23 </dependency> 24 </dependency>
  25 +
  26 + <!-- Web 相关 -->
  27 + <dependency>
  28 + <groupId>org.springframework</groupId>
  29 + <artifactId>spring-web</artifactId>
  30 + <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
  31 + </dependency>
  32 +
  33 + <!-- 工具类相关 -->
  34 + <dependency>
  35 + <groupId>com.fasterxml.jackson.core</groupId>
  36 + <artifactId>jackson-databind</artifactId>
  37 + <scope>provided</scope> <!-- 设置为 provided,只有工具类需要使用到 -->
  38 + </dependency>
  39 +
  40 + <dependency>
  41 + <groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
  42 + <artifactId>pf4j-spring</artifactId>
  43 + </dependency>
  44 +
  45 + <!-- 参数校验 -->
  46 + <dependency>
  47 + <groupId>org.springframework.boot</groupId>
  48 + <artifactId>spring-boot-starter-validation</artifactId>
  49 + <optional>true</optional>
  50 + </dependency>
24 </dependencies> 51 </dependencies>
25 52
26 </project> 53 </project>
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/IotDeviceUpstreamApi.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
  5 +import cn.iocoder.yudao.module.iot.enums.ApiConstants;
  6 +import jakarta.validation.Valid;
  7 +import org.springframework.web.bind.annotation.PostMapping;
  8 +import org.springframework.web.bind.annotation.RequestBody;
  9 +
  10 +/**
  11 + * 设备数据 Upstream 上行 API
  12 + *
  13 + * 目的:设备 -> 插件 -> 服务端
  14 + *
  15 + * @author haohao
  16 + */
  17 +public interface IotDeviceUpstreamApi {
  18 +
  19 + String PREFIX = ApiConstants.PREFIX + "/device/upstream";
  20 +
  21 + // ========== 设备相关 ==========
  22 +
  23 + /**
  24 + * 更新设备状态
  25 + *
  26 + * @param updateReqDTO 更新设备状态 DTO
  27 + */
  28 + @PostMapping(PREFIX + "/update-state")
  29 + CommonResult<Boolean> updateDeviceState(@Valid @RequestBody IotDeviceStateUpdateReqDTO updateReqDTO);
  30 +
  31 + /**
  32 + * 上报设备属性数据
  33 + *
  34 + * @param reportReqDTO 上报设备属性数据 DTO
  35 + */
  36 + @PostMapping(PREFIX + "/report-property")
  37 + CommonResult<Boolean> reportDeviceProperty(@Valid @RequestBody IotDevicePropertyReportReqDTO reportReqDTO);
  38 +
  39 + /**
  40 + * 上报设备事件数据
  41 + *
  42 + * @param reportReqDTO 设备事件
  43 + */
  44 + @PostMapping(PREFIX + "/report-event")
  45 + CommonResult<Boolean> reportDeviceEvent(@Valid @RequestBody IotDeviceEventReportReqDTO reportReqDTO);
  46 +
  47 + // TODO @芋艿:这个需要 plugins 接入下
  48 + /**
  49 + * 注册设备
  50 + *
  51 + * @param registerReqDTO 注册设备 DTO
  52 + */
  53 + @PostMapping(PREFIX + "/register")
  54 + CommonResult<Boolean> registerDevice(@Valid @RequestBody IotDeviceRegisterReqDTO registerReqDTO);
  55 +
  56 + // TODO @芋艿:这个需要 plugins 接入下
  57 + /**
  58 + * 注册子设备
  59 + *
  60 + * @param registerReqDTO 注册子设备 DTO
  61 + */
  62 + @PostMapping(PREFIX + "/register-sub")
  63 + CommonResult<Boolean> registerSubDevice(@Valid @RequestBody IotDeviceRegisterSubReqDTO registerReqDTO);
  64 +
  65 + // TODO @芋艿:这个需要 plugins 接入下
  66 + /**
  67 + * 注册设备拓扑
  68 + *
  69 + * @param addReqDTO 注册设备拓扑 DTO
  70 + */
  71 + @PostMapping(PREFIX + "/add-topology")
  72 + CommonResult<Boolean> addDeviceTopology(@Valid @RequestBody IotDeviceTopologyAddReqDTO addReqDTO);
  73 +
  74 + // TODO @芋艿:考虑 http 认证
  75 + /**
  76 + * 认证 Emqx 连接
  77 + *
  78 + * @param authReqDTO 认证 Emqx 连接 DTO
  79 + */
  80 + @PostMapping(PREFIX + "/authenticate-emqx-connection")
  81 + CommonResult<Boolean> authenticateEmqxConnection(@Valid @RequestBody IotDeviceEmqxAuthReqDTO authReqDTO);
  82 +
  83 + // ========== 插件相关 ==========
  84 +
  85 + /**
  86 + * 心跳插件实例
  87 + *
  88 + * @param heartbeatReqDTO 心跳插件实例 DTO
  89 + */
  90 + @PostMapping(PREFIX + "/heartbeat-plugin-instance")
  91 + CommonResult<Boolean> heartbeatPluginInstance(@Valid @RequestBody IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO);
  92 +
  93 +}
0 \ No newline at end of file 94 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceConfigSetReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotNull;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【配置】设置 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceConfigSetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 配置
  18 + */
  19 + @NotNull(message = "配置不能为空")
  20 + private Map<String, Object> config;
  21 +
  22 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceDownstreamAbstractReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +/**
  7 + * IoT 设备下行的抽象 Request DTO
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Data
  12 +public abstract class IotDeviceDownstreamAbstractReqDTO {
  13 +
  14 + /**
  15 + * 请求编号
  16 + */
  17 + private String requestId;
  18 +
  19 + /**
  20 + * 产品标识
  21 + */
  22 + @NotEmpty(message = "产品标识不能为空")
  23 + private String productKey;
  24 + /**
  25 + * 设备名称
  26 + */
  27 + @NotEmpty(message = "设备名称不能为空")
  28 + private String deviceName;
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceOtaUpgradeReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import cn.hutool.core.map.MapUtil;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【OTA】升级下发 Request DTO(更新固件消息)
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceOtaUpgradeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 固件编号
  18 + */
  19 + private Long firmwareId;
  20 + /**
  21 + * 固件版本
  22 + */
  23 + private String version;
  24 +
  25 + /**
  26 + * 签名方式
  27 + *
  28 + * 例如说:MD5、SHA256
  29 + */
  30 + private String signMethod;
  31 + /**
  32 + * 固件文件签名
  33 + */
  34 + private String fileSign;
  35 + /**
  36 + * 固件文件大小
  37 + */
  38 + private Long fileSize;
  39 + /**
  40 + * 固件文件 URL
  41 + */
  42 + private String fileUrl;
  43 +
  44 + /**
  45 + * 自定义信息,建议使用 JSON 格式
  46 + */
  47 + private String information;
  48 +
  49 + public static IotDeviceOtaUpgradeReqDTO build(Map<?, ?> map) {
  50 + return new IotDeviceOtaUpgradeReqDTO()
  51 + .setFirmwareId(MapUtil.getLong(map, "firmwareId")).setVersion((String) map.get("version"))
  52 + .setSignMethod((String) map.get("signMethod")).setFileSign((String) map.get("fileSign"))
  53 + .setFileSize(MapUtil.getLong(map, "fileSize")).setFileUrl((String) map.get("fileUrl"))
  54 + .setInformation((String) map.get("information"));
  55 + }
  56 +
  57 + public static Map<?, ?> build(IotDeviceOtaUpgradeReqDTO dto) {
  58 + return MapUtil.builder()
  59 + .put("firmwareId", dto.getFirmwareId()).put("version", dto.getVersion())
  60 + .put("signMethod", dto.getSignMethod()).put("fileSign", dto.getFileSign())
  61 + .put("fileSize", dto.getFileSize()).put("fileUrl", dto.getFileUrl())
  62 + .put("information", dto.getInformation())
  63 + .build();
  64 + }
  65 +
  66 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertyGetReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +// TODO @芋艿:从 server => plugin => device 是否有必要?从阿里云 iot 来看,没有这个功能?!
  9 +// TODO @芋艿:是不是改成 read 更好?在看看阿里云的 topic 设计
  10 +/**
  11 + * IoT 设备【属性】获取 Request DTO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Data
  16 +public class IotDevicePropertyGetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  17 +
  18 + /**
  19 + * 属性标识数组
  20 + */
  21 + @NotEmpty(message = "属性标识数组不能为空")
  22 + private List<String> identifiers;
  23 +
  24 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDevicePropertySetReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【属性】设置 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDevicePropertySetReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 属性参数
  18 + */
  19 + @NotEmpty(message = "属性参数不能为空")
  20 + private Map<String, Object> properties;
  21 +
  22 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/downstream/IotDeviceServiceInvokeReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.downstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【服务】调用 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceServiceInvokeReqDTO extends IotDeviceDownstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 服务标识
  18 + */
  19 + @NotEmpty(message = "服务标识不能为空")
  20 + private String identifier;
  21 + /**
  22 + * 调用参数
  23 + */
  24 + private Map<String, Object> params;
  25 +
  26 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEmqxAuthReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +// TODO @芋艿:要不要继承 IotDeviceUpstreamAbstractReqDTO
  7 +// TODO @芋艿:@haohao:后续其它认证的设计
  8 +/**
  9 + * IoT 认证 Emqx 连接 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceEmqxAuthReqDTO {
  15 +
  16 + /**
  17 + * 客户端 ID
  18 + */
  19 + @NotEmpty(message = "客户端 ID 不能为空")
  20 + private String clientId;
  21 +
  22 + /**
  23 + * 用户名
  24 + */
  25 + @NotEmpty(message = "用户名不能为空")
  26 + private String username;
  27 +
  28 + /**
  29 + * 密码
  30 + */
  31 + @NotEmpty(message = "密码不能为空")
  32 + private String password;
  33 +
  34 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceEventReportReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【事件】上报 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceEventReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 事件标识
  18 + */
  19 + @NotEmpty(message = "事件标识不能为空")
  20 + private String identifier;
  21 + /**
  22 + * 事件参数
  23 + */
  24 + private Map<String, Object> params;
  25 +
  26 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaProgressReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import lombok.Data;
  4 +
  5 +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/progress
  6 +/**
  7 + * IoT 设备【OTA】升级进度 Request DTO(上报更新固件进度)
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Data
  12 +public class IotDeviceOtaProgressReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  13 +
  14 + /**
  15 + * 固件编号
  16 + */
  17 + private Long firmwareId;
  18 +
  19 + /**
  20 + * 升级状态
  21 + *
  22 + * 枚举 {@link cn.iocoder.yudao.module.iot.enums.ota.IotOtaUpgradeRecordStatusEnum}
  23 + */
  24 + private Integer status;
  25 + /**
  26 + * 升级进度,百分比
  27 + */
  28 + private Integer progress;
  29 +
  30 + /**
  31 + * 升级进度描述
  32 + */
  33 + private String description;
  34 +
  35 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaPullReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/pull
  4 +/**
  5 + * IoT 设备【OTA】升级下拉 Request DTO(拉取固件更新)
  6 + *
  7 + * @author 芋道源码
  8 + */
  9 +public class IotDeviceOtaPullReqDTO {
  10 +
  11 + /**
  12 + * 固件编号
  13 + */
  14 + private Long firmwareId;
  15 +
  16 + /**
  17 + * 固件版本
  18 + */
  19 + private String version;
  20 +
  21 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceOtaReportReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +// TODO @芋艿:待实现:/ota/${productKey}/${deviceName}/report
  4 +/**
  5 + * IoT 设备【OTA】上报 Request DTO(上报固件版本)
  6 + *
  7 + * @author 芋道源码
  8 + */
  9 +public class IotDeviceOtaReportReqDTO {
  10 +
  11 + /**
  12 + * 固件编号
  13 + */
  14 + private Long firmwareId;
  15 +
  16 + /**
  17 + * 固件版本
  18 + */
  19 + private String version;
  20 +
  21 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDevicePropertyReportReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.Map;
  7 +
  8 +/**
  9 + * IoT 设备【属性】上报 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDevicePropertyReportReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 属性参数
  18 + */
  19 + @NotEmpty(message = "属性参数不能为空")
  20 + private Map<String, Object> properties;
  21 +
  22 +}
0 \ No newline at end of file 23 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import lombok.Data;
  4 +
  5 +/**
  6 + * IoT 设备【注册】自己 Request DTO
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +@Data
  11 +public class IotDeviceRegisterReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  12 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceRegisterSubReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * IoT 设备【注册】子设备 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceRegisterSubReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + // TODO @芋艿:看看要不要优化命名
  17 + /**
  18 + * 子设备数组
  19 + */
  20 + @NotEmpty(message = "子设备不能为空")
  21 + private List<Device> params;
  22 +
  23 + /**
  24 + * 设备信息
  25 + */
  26 + @Data
  27 + public static class Device {
  28 +
  29 + /**
  30 + * 产品标识
  31 + */
  32 + @NotEmpty(message = "产品标识不能为空")
  33 + private String productKey;
  34 +
  35 + /**
  36 + * 设备名称
  37 + */
  38 + @NotEmpty(message = "设备名称不能为空")
  39 + private String deviceName;
  40 +
  41 + }
  42 +
  43 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceStateUpdateReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +/**
  9 + * IoT 设备【状态】更新 Request DTO
  10 + *
  11 + * @author 芋道源码
  12 + */
  13 +@Data
  14 +public class IotDeviceStateUpdateReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  15 +
  16 + /**
  17 + * 设备状态
  18 + */
  19 + @NotNull(message = "设备状态不能为空")
  20 + @InEnum(IotDeviceStateEnum.class) // 只使用:在线、离线
  21 + private Integer state;
  22 +
  23 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceTopologyAddReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import lombok.Data;
  5 +
  6 +import java.util.List;
  7 +
  8 +// TODO @芋艿:要写清楚,是来自设备网关,还是设备。
  9 +/**
  10 + * IoT 设备【拓扑】添加 Request DTO
  11 + */
  12 +@Data
  13 +public class IotDeviceTopologyAddReqDTO extends IotDeviceUpstreamAbstractReqDTO {
  14 +
  15 + // TODO @芋艿:看看要不要优化命名
  16 + /**
  17 + * 子设备数组
  18 + */
  19 + @NotEmpty(message = "子设备不能为空")
  20 + private List<IotDeviceRegisterSubReqDTO.Device> params;
  21 +
  22 + /**
  23 + * 设备信息
  24 + */
  25 + @Data
  26 + public static class Device {
  27 +
  28 + /**
  29 + * 产品标识
  30 + */
  31 + @NotEmpty(message = "产品标识不能为空")
  32 + private String productKey;
  33 +
  34 + /**
  35 + * 设备名称
  36 + */
  37 + @NotEmpty(message = "设备名称不能为空")
  38 + private String deviceName;
  39 +
  40 + // TODO @芋艿:阿里云还有 sign 签名
  41 +
  42 + }
  43 +
  44 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotDeviceUpstreamAbstractReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.json.databind.TimestampLocalDateTimeSerializer;
  4 +import com.fasterxml.jackson.databind.annotation.JsonSerialize;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import lombok.Data;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +/**
  11 + * IoT 设备上行的抽象 Request DTO
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Data
  16 +public abstract class IotDeviceUpstreamAbstractReqDTO {
  17 +
  18 + /**
  19 + * 请求编号
  20 + */
  21 + private String requestId;
  22 +
  23 + /**
  24 + * 插件实例的进程编号
  25 + */
  26 + private String processId;
  27 +
  28 + /**
  29 + * 产品标识
  30 + */
  31 + @NotEmpty(message = "产品标识不能为空")
  32 + private String productKey;
  33 + /**
  34 + * 设备名称
  35 + */
  36 + @NotEmpty(message = "设备名称不能为空")
  37 + private String deviceName;
  38 +
  39 + /**
  40 + * 上报时间
  41 + */
  42 + @JsonSerialize(using = TimestampLocalDateTimeSerializer.class) // 解决 iot plugins 序列化 LocalDateTime 是数组,导致无法解析的问题
  43 + private LocalDateTime reportTime;
  44 +
  45 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/control/upstream/IotPluginInstanceHeartbeatReqDTO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device.dto.control.upstream;
  2 +
  3 +import jakarta.validation.constraints.NotEmpty;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +
  7 +/**
  8 + * IoT 插件实例心跳 Request DTO
  9 + *
  10 + * @author 芋道源码
  11 + */
  12 +@Data
  13 +public class IotPluginInstanceHeartbeatReqDTO {
  14 +
  15 + /**
  16 + * 请求编号
  17 + */
  18 + @NotEmpty(message = "请求编号不能为空")
  19 + private String processId;
  20 +
  21 + /**
  22 + * 插件包标识符
  23 + */
  24 + @NotEmpty(message = "插件包标识符不能为空")
  25 + private String pluginKey;
  26 +
  27 + /**
  28 + * 插件实例所在 IP
  29 + */
  30 + @NotEmpty(message = "插件实例所在 IP 不能为空")
  31 + private String hostIp;
  32 + /**
  33 + * 插件实例的进程编号
  34 + */
  35 + @NotNull(message = "插件实例的进程编号不能为空")
  36 + private Integer downstreamPort;
  37 +
  38 + /**
  39 + * 是否在线
  40 + */
  41 + @NotNull(message = "是否在线不能为空")
  42 + private Boolean online;
  43 +
  44 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/api/device/dto/package-info.java 0 → 100644
  1 +/**
  2 + * TODO 芋艿:占位
  3 + */
  4 +package cn.iocoder.yudao.module.iot.api.device.dto;
0 \ No newline at end of file 5 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ApiConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.RpcConstants;
  4 +
  5 +/**
  6 + * API 相关的枚举
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public class ApiConstants {
  11 +
  12 + public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/iot";
  13 +
  14 + public static final String VERSION = "1.0.0";
  15 +
  16 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/DictTypeConstants.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums;
  2 +
  3 +/**
  4 + * IoT 字典类型的枚举类
  5 + *
  6 + * @author 芋道源码
  7 + */
  8 +public class DictTypeConstants {
  9 +
  10 + public static final String PRODUCT_STATUS = "iot_product_status";
  11 + public static final String PRODUCT_DEVICE_TYPE = "iot_product_device_type";
  12 + public static final String NET_TYPE = "iot_net_type";
  13 + public static final String PROTOCOL_TYPE = "iot_protocol_type";
  14 + public static final String DATA_FORMAT = "iot_data_format";
  15 + public static final String VALIDATE_TYPE = "iot_validate_type";
  16 +
  17 + public static final String DEVICE_STATE = "iot_device_state";
  18 +
  19 + public static final String IOT_DATA_BRIDGE_DIRECTION_ENUM = "iot_data_bridge_direction_enum";
  20 + public static final String IOT_DATA_BRIDGE_TYPE_ENUM = "iot_data_bridge_type_enum";
  21 +
  22 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
@@ -9,24 +9,67 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; @@ -9,24 +9,67 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode;
9 */ 9 */
10 public interface ErrorCodeConstants { 10 public interface ErrorCodeConstants {
11 11
12 - // ========== IoT 产品相关 1-050-001-000 ============ 12 + // ========== 产品相关 1-050-001-000 ============
13 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在"); 13 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_050_001_000, "产品不存在");
14 - ErrorCode PRODUCT_IDENTIFICATION_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在"); 14 + ErrorCode PRODUCT_KEY_EXISTS = new ErrorCode(1_050_001_001, "产品标识已经存在");
15 ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除"); 15 ErrorCode PRODUCT_STATUS_NOT_DELETE = new ErrorCode(1_050_001_002, "产品状是发布状态,不允许删除");
  16 + ErrorCode PRODUCT_STATUS_NOT_ALLOW_THING_MODEL = new ErrorCode(1_050_001_003, "产品状是发布状态,不允许操作物模型");
16 17
17 - // ========== IoT 产品物模型 1-050-002-000 ============  
18 - ErrorCode THINK_MODEL_FUNCTION_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");  
19 - ErrorCode THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");  
20 - ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");  
21 - ErrorCode THINK_MODEL_FUNCTION_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");  
22 - ErrorCode THINK_MODEL_FUNCTION_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效"); 18 + // ========== 产品物模型 1-050-002-000 ============
  19 + ErrorCode THING_MODEL_NOT_EXISTS = new ErrorCode(1_050_002_000, "产品物模型不存在");
  20 + ErrorCode THING_MODEL_EXISTS_BY_PRODUCT_KEY = new ErrorCode(1_050_002_001, "ProductKey 对应的产品物模型已存在");
  21 + ErrorCode THING_MODEL_IDENTIFIER_EXISTS = new ErrorCode(1_050_002_002, "存在重复的功能标识符。");
  22 + ErrorCode THING_MODEL_NAME_EXISTS = new ErrorCode(1_050_002_003, "存在重复的功能名称。");
  23 + ErrorCode THING_MODEL_IDENTIFIER_INVALID = new ErrorCode(1_050_002_003, "产品物模型标识无效");
23 24
24 - // ========== IoT 设备 1-050-003-000 ============ 25 + // ========== 设备 1-050-003-000 ============
25 ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); 26 ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在");
26 ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一"); 27 ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一");
27 ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除"); 28 ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除");
28 - ErrorCode DEVICE_NAME_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_003, "设备名称不能修改");  
29 - ErrorCode DEVICE_PRODUCT_CANNOT_BE_MODIFIED = new ErrorCode(1_050_003_004, "产品不能修改");  
30 - ErrorCode DEVICE_INVALID_DEVICE_STATUS = new ErrorCode(1_050_003_005, "无效的设备状态"); 29 + ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在");
  30 + ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在");
  31 + ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备");
  32 + ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!");
  33 + ErrorCode DEVICE_DOWNSTREAM_FAILED = new ErrorCode(1_050_003_007, "执行失败,原因:{}");
31 34
32 -} 35 + // ========== 产品分类 1-050-004-000 ==========
  36 + ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在");
  37 +
  38 + // ========== 设备分组 1-050-005-000 ==========
  39 + ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
  40 + ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
  41 +
  42 + // ========== 插件配置 1-050-006-000 ==========
  43 + ErrorCode PLUGIN_CONFIG_NOT_EXISTS = new ErrorCode(1_050_006_000, "插件配置不存在");
  44 + ErrorCode PLUGIN_INSTALL_FAILED = new ErrorCode(1_050_006_001, "插件安装失败");
  45 + ErrorCode PLUGIN_INSTALL_FAILED_FILE_NAME_NOT_MATCH = new ErrorCode(1_050_006_002, "插件安装失败,文件名与原插件id不匹配");
  46 + ErrorCode PLUGIN_CONFIG_DELETE_FAILED_RUNNING = new ErrorCode(1_050_006_003, "请先停止插件");
  47 + ErrorCode PLUGIN_STATUS_INVALID = new ErrorCode(1_050_006_004, "插件状态无效");
  48 + ErrorCode PLUGIN_CONFIG_KEY_DUPLICATE = new ErrorCode(1_050_006_005, "插件标识已存在");
  49 + ErrorCode PLUGIN_START_FAILED = new ErrorCode(1_050_006_006, "插件启动失败");
  50 + ErrorCode PLUGIN_STOP_FAILED = new ErrorCode(1_050_006_007, "插件停止失败");
  51 +
  52 + // ========== 插件实例 1-050-007-000 ==========
  53 +
  54 + // ========== 固件相关 1-050-008-000 ==========
  55 +
  56 + ErrorCode OTA_FIRMWARE_NOT_EXISTS = new ErrorCode(1_050_008_000, "固件信息不存在");
  57 + ErrorCode OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE = new ErrorCode(1_050_008_001, "产品版本号重复");
  58 +
  59 + ErrorCode OTA_UPGRADE_TASK_NOT_EXISTS = new ErrorCode(1_050_008_100, "升级任务不存在");
  60 + ErrorCode OTA_UPGRADE_TASK_NAME_DUPLICATE = new ErrorCode(1_050_008_101, "升级任务名称重复");
  61 + ErrorCode OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY = new ErrorCode(1_050_008_102, "设备编号列表不能为空");
  62 + ErrorCode OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY = new ErrorCode(1_050_008_103, "设备列表不能为空");
  63 + ErrorCode OTA_UPGRADE_TASK_CANNOT_CANCEL = new ErrorCode(1_050_008_104, "升级任务不能取消");
  64 +
  65 + ErrorCode OTA_UPGRADE_RECORD_NOT_EXISTS = new ErrorCode(1_050_008_200, "升级记录不存在");
  66 + ErrorCode OTA_UPGRADE_RECORD_DUPLICATE = new ErrorCode(1_050_008_201, "升级记录重复");
  67 + ErrorCode OTA_UPGRADE_RECORD_CANNOT_RETRY = new ErrorCode(1_050_008_202, "升级记录不能重试");
  68 +
  69 + // ========== MQTT 通信相关 1-050-009-000 ==========
  70 + ErrorCode MQTT_TOPIC_ILLEGAL = new ErrorCode(1_050_009_000, "topic illegal");
  71 +
  72 + // ========== IoT 数据桥梁 1-050-010-000 ==========
  73 + ErrorCode DATA_BRIDGE_NOT_EXISTS = new ErrorCode(1_050_010_000, "IoT 数据桥梁不存在");
  74 +
  75 +}
33 \ No newline at end of file 76 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageIdentifierEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
  5 +
  6 +// TODO @芋艿:需要添加对应的 DTO,以及上下行的链路,网关、网关服务、设备等
  7 +/**
  8 + * IoT 设备消息标识符枚举
  9 + */
  10 +@Getter
  11 +@RequiredArgsConstructor
  12 +public enum IotDeviceMessageIdentifierEnum {
  13 +
  14 + PROPERTY_GET("get"), // 下行 TODO 芋艿:【讨论】貌似这个“上行”更合理?device 主动拉取配置。和 IotDevicePropertyGetReqDTO 一样的配置
  15 + PROPERTY_SET("set"), // 下行
  16 + PROPERTY_REPORT("report"), // 上行
  17 +
  18 + STATE_ONLINE("online"), // 上行
  19 + STATE_OFFLINE("offline"), // 上行
  20 +
  21 + CONFIG_GET("get"), // 上行 TODO 芋艿:【讨论】暂时没有上行的场景
  22 + CONFIG_SET("set"), // 下行
  23 +
  24 + SERVICE_INVOKE("${identifier}"), // 下行
  25 + SERVICE_REPLY_SUFFIX("_reply"), // 芋艿:TODO 芋艿:【讨论】上行 or 下行
  26 +
  27 + OTA_UPGRADE("upgrade"), // 下行
  28 + OTA_PULL("pull"), // 上行
  29 + OTA_PROGRESS("progress"), // 上行
  30 + OTA_REPORT("report"), // 上行
  31 +
  32 + REGISTER_REGISTER("register"), // 上行
  33 + REGISTER_REGISTER_SUB("register_sub"), // 上行
  34 + REGISTER_UNREGISTER_SUB("unregister_sub"), // 下行
  35 +
  36 + TOPOLOGY_ADD("topology_add"), // 下行;
  37 + ;
  38 +
  39 + /**
  40 + * 标志符
  41 + */
  42 + private final String identifier;
  43 +
  44 +}
0 \ No newline at end of file 45 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceMessageTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 设备消息类型枚举
  11 + */
  12 +@Getter
  13 +@RequiredArgsConstructor
  14 +public enum IotDeviceMessageTypeEnum implements ArrayValuable<String> {
  15 +
  16 + STATE("state"), // 设备状态
  17 + PROPERTY("property"), // 设备属性:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
  18 + EVENT("event"), // 设备事件:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
  19 + SERVICE("service"), // 设备服务:可参考 https://help.aliyun.com/zh/iot/user-guide/device-properties-events-and-services 设备属性、事件、服务
  20 + CONFIG("config"), // 设备配置:可参考 https://help.aliyun.com/zh/iot/user-guide/remote-configuration-1 远程配置
  21 + OTA("ota"), // 设备 OTA:可参考 https://help.aliyun.com/zh/iot/user-guide/ota-update OTA 升级
  22 + REGISTER("register"), // 设备注册:可参考 https://help.aliyun.com/zh/iot/user-guide/register-devices 设备身份注册
  23 + TOPOLOGY("topology"),; // 设备拓扑:可参考 https://help.aliyun.com/zh/iot/user-guide/manage-topological-relationships 设备拓扑
  24 +
  25 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDeviceMessageTypeEnum::getType).toArray(String[]::new);
  26 +
  27 + /**
  28 + * 属性
  29 + */
  30 + private final String type;
  31 +
  32 + @Override
  33 + public String[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStatusEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotDeviceStateEnum.java
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.enums.device; @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.iot.enums.device;
2 2
3 import cn.iocoder.yudao.framework.common.core.ArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4 import lombok.Getter; 4 import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
5 6
6 import java.util.Arrays; 7 import java.util.Arrays;
7 8
@@ -10,46 +11,32 @@ import java.util.Arrays; @@ -10,46 +11,32 @@ import java.util.Arrays;
10 * 11 *
11 * @author haohao 12 * @author haohao
12 */ 13 */
  14 +@RequiredArgsConstructor
13 @Getter 15 @Getter
14 -public enum IotDeviceStatusEnum implements ArrayValuable<Integer> { 16 +public enum IotDeviceStateEnum implements ArrayValuable<Integer> {
15 17
16 INACTIVE(0, "未激活"), 18 INACTIVE(0, "未激活"),
17 ONLINE(1, "在线"), 19 ONLINE(1, "在线"),
18 - OFFLINE(2, "离线"),  
19 - DISABLED(3, "已禁用"); 20 + OFFLINE(2, "离线");
20 21
21 - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDeviceStatusEnum::getStatus).toArray(Integer[]::new); 22 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDeviceStateEnum::getState).toArray(Integer[]::new);
22 23
23 /** 24 /**
24 * 状态 25 * 状态
25 */ 26 */
26 - private final Integer status; 27 + private final Integer state;
27 /** 28 /**
28 * 状态名 29 * 状态名
29 */ 30 */
30 private final String name; 31 private final String name;
31 32
32 - IotDeviceStatusEnum(Integer status, String name) {  
33 - this.status = status;  
34 - this.name = name;  
35 - }  
36 -  
37 - public static IotDeviceStatusEnum fromStatus(Integer status) {  
38 - for (IotDeviceStatusEnum value : values()) {  
39 - if (value.getStatus().equals(status)) {  
40 - return value;  
41 - }  
42 - }  
43 - return null;  
44 - }  
45 -  
46 - public static boolean isValidStatus(Integer status) {  
47 - return fromStatus(status) != null;  
48 - }  
49 -  
50 @Override 33 @Override
51 public Integer[] array() { 34 public Integer[] array() {
52 return ARRAYS; 35 return ARRAYS;
53 } 36 }
54 37
  38 + public static boolean isOnline(Integer state) {
  39 + return ONLINE.getState().equals(state);
  40 + }
  41 +
55 } 42 }
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeRecordStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.ota;
  2 +
  3 +
  4 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import lombok.Getter;
  6 +import lombok.RequiredArgsConstructor;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * IoT OTA 升级记录的范围枚举
  12 + *
  13 + * @author haohao
  14 + */
  15 +@RequiredArgsConstructor
  16 +@Getter
  17 +public enum IotOtaUpgradeRecordStatusEnum implements ArrayValuable<Integer> {
  18 +
  19 + PENDING(0), // 待推送
  20 + PUSHED(10), // 已推送
  21 + UPGRADING(20), // 升级中
  22 + SUCCESS(30), // 升级成功
  23 + FAILURE(40), // 升级失败
  24 + CANCELED(50),; // 已取消
  25 +
  26 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeRecordStatusEnum::getStatus).toArray(Integer[]::new);
  27 +
  28 + /**
  29 + * 范围
  30 + */
  31 + private final Integer status;
  32 +
  33 + @Override
  34 + public Integer[] array() {
  35 + return ARRAYS;
  36 + }
  37 +
  38 +}
0 \ No newline at end of file 39 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskScopeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT OTA 升级任务的范围枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotOtaUpgradeTaskScopeEnum implements ArrayValuable<Integer> {
  17 +
  18 + ALL(1), // 全部设备:只包括当前产品下的设备,不包括未来创建的设备
  19 + SELECT(2); // 指定设备
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskScopeEnum::getScope).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 范围
  25 + */
  26 + private final Integer scope;
  27 +
  28 + @Override
  29 + public Integer[] array() {
  30 + return ARRAYS;
  31 + }
  32 +
  33 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ota/IotOtaUpgradeTaskStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT OTA 升级任务的范围枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotOtaUpgradeTaskStatusEnum implements ArrayValuable<Integer> {
  17 +
  18 + IN_PROGRESS(10), // 进行中:升级中
  19 + COMPLETED(20), // 已完成:已结束,全部升级完成
  20 + INCOMPLETE(21), // 未完成:已结束,部分升级完成
  21 + CANCELED(30),; // 已取消:一般是主动取消任务
  22 +
  23 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotOtaUpgradeTaskStatusEnum::getStatus).toArray(Integer[]::new);
  24 +
  25 + /**
  26 + * 范围
  27 + */
  28 + private final Integer status;
  29 +
  30 + @Override
  31 + public Integer[] array() {
  32 + return ARRAYS;
  33 + }
  34 +
  35 +}
0 \ No newline at end of file 36 \ No newline at end of file
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginDeployTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 部署方式枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotPluginDeployTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + JAR(0, "JAR 部署"),
  19 + STANDALONE(1, "独立部署");
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginDeployTypeEnum::getDeployType).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 部署方式
  25 + */
  26 + private final Integer deployType;
  27 + /**
  28 + * 部署方式名
  29 + */
  30 + private final String name;
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginStatusEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 插件状态枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotPluginStatusEnum implements ArrayValuable<Integer> {
  17 +
  18 + STOPPED(0, "停止"),
  19 + RUNNING(1, "运行");
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginStatusEnum::getStatus).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 状态
  25 + */
  26 + private final Integer status;
  27 + /**
  28 + * 状态名
  29 + */
  30 + private final String name;
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/plugin/IotPluginTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.plugin;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 插件类型枚举
  11 + *
  12 + * @author haohao
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotPluginTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + NORMAL(0, "普通插件"),
  19 + DEVICE(1, "设备插件");
  20 +
  21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotPluginTypeEnum::getType).toArray(Integer[]::new);
  22 +
  23 + /**
  24 + * 类型
  25 + */
  26 + private final Integer type;
  27 + /**
  28 + * 类型名
  29 + */
  30 + private final String name;
  31 +
  32 + @Override
  33 + public Integer[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotNetTypeEnum.java
@@ -7,7 +7,7 @@ import lombok.Getter; @@ -7,7 +7,7 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * IOT 联网方式枚举类 10 + * IoT 联网方式枚举类
11 * 11 *
12 * @author ahh 12 * @author ahh
13 */ 13 */
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductDeviceTypeEnum.java
@@ -7,7 +7,7 @@ import lombok.Getter; @@ -7,7 +7,7 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * IOT 产品的设备类型 10 + * IoT 产品的设备类型
11 * 11 *
12 * @author ahh 12 * @author ahh
13 */ 13 */
@@ -16,7 +16,7 @@ import java.util.Arrays; @@ -16,7 +16,7 @@ import java.util.Arrays;
16 public enum IotProductDeviceTypeEnum implements ArrayValuable<Integer> { 16 public enum IotProductDeviceTypeEnum implements ArrayValuable<Integer> {
17 17
18 DIRECT(0, "直连设备"), 18 DIRECT(0, "直连设备"),
19 - GATEWAY_CHILD(1, "网关子设备"), 19 + GATEWAY_SUB(1, "网关子设备"),
20 GATEWAY(2, "网关设备"); 20 GATEWAY(2, "网关设备");
21 21
22 /** 22 /**
@@ -36,4 +36,24 @@ public enum IotProductDeviceTypeEnum implements ArrayValuable&lt;Integer&gt; { @@ -36,4 +36,24 @@ public enum IotProductDeviceTypeEnum implements ArrayValuable&lt;Integer&gt; {
36 return ARRAYS; 36 return ARRAYS;
37 } 37 }
38 38
  39 + /**
  40 + * 判断是否是网关
  41 + *
  42 + * @param type 类型
  43 + * @return 是否是网关
  44 + */
  45 + public static boolean isGateway(Integer type) {
  46 + return GATEWAY.getType().equals(type);
  47 + }
  48 +
  49 + /**
  50 + * 判断是否是网关子设备
  51 + *
  52 + * @param type 类型
  53 + * @return 是否是网关子设备
  54 + */
  55 + public static boolean isGatewaySub(Integer type) {
  56 + return GATEWAY_SUB.getType().equals(type);
  57 + }
  58 +
39 } 59 }
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductStatusEnum.java
@@ -7,7 +7,7 @@ import lombok.Getter; @@ -7,7 +7,7 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * IOT 产品的状态枚举类 10 + * IoT 产品的状态枚举类
11 * 11 *
12 * @author ahh 12 * @author ahh
13 */ 13 */
@@ -18,12 +18,12 @@ public enum IotProductStatusEnum implements ArrayValuable&lt;Integer&gt; { @@ -18,12 +18,12 @@ public enum IotProductStatusEnum implements ArrayValuable&lt;Integer&gt; {
18 UNPUBLISHED(0, "开发中"), 18 UNPUBLISHED(0, "开发中"),
19 PUBLISHED(1, "已发布"); 19 PUBLISHED(1, "已发布");
20 20
21 - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductStatusEnum::getType).toArray(Integer[]::new); 21 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductStatusEnum::getStatus).toArray(Integer[]::new);
22 22
23 /** 23 /**
24 * 类型 24 * 类型
25 */ 25 */
26 - private final Integer type; 26 + private final Integer status;
27 /** 27 /**
28 * 描述 28 * 描述
29 */ 29 */
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProtocolTypeEnum.java
@@ -7,7 +7,7 @@ import lombok.Getter; @@ -7,7 +7,7 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * IOT 接入网关协议枚举类 10 + * IoT 接入网关协议枚举类
11 * 11 *
12 * @author ahh 12 * @author ahh
13 */ 13 */
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotValidateTypeEnum.java
@@ -7,7 +7,7 @@ import lombok.Getter; @@ -7,7 +7,7 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * IOT 数据校验级别枚举类 10 + * IoT 数据校验级别枚举类
11 * 11 *
12 * @author ahh 12 * @author ahh
13 */ 13 */
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotAlertConfigReceiveTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 告警配置的接收方式枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotAlertConfigReceiveTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + SMS(1), // 短信
  19 + MAIL(2), // 邮箱
  20 + NOTIFY(3); // 通知
  21 +
  22 + private final Integer type;
  23 +
  24 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotAlertConfigReceiveTypeEnum::getType).toArray(Integer[]::new);
  25 +
  26 + @Override
  27 + public Integer[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeDirectionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 数据桥接的方向枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotDataBridgeDirectionEnum implements ArrayValuable<Integer> {
  17 +
  18 + INPUT(1), // 输入
  19 + OUTPUT(2); // 输出
  20 +
  21 + private final Integer type;
  22 +
  23 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeDirectionEnum::getType).toArray(Integer[]::new);
  24 +
  25 + @Override
  26 + public Integer[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotDataBridgeTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 数据桥接的类型枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotDataBridgeTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + HTTP(1, "HTTP"),
  19 + TCP(2, "TCP"),
  20 + WEBSOCKET(3, "WEBSOCKET"),
  21 +
  22 + MQTT(10, "MQTT"),
  23 +
  24 + DATABASE(20, "DATABASE"),
  25 + REDIS_STREAM(21, "REDIS_STREAM"),
  26 +
  27 + ROCKETMQ(30, "ROCKETMQ"),
  28 + RABBITMQ(31, "RABBITMQ"),
  29 + KAFKA(32, "KAFKA");
  30 +
  31 + private final Integer type;
  32 +
  33 + private final String name;
  34 +
  35 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotDataBridgeTypeEnum::getType).toArray(Integer[]::new);
  36 +
  37 + @Override
  38 + public Integer[] array() {
  39 + return ARRAYS;
  40 + }
  41 +
  42 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 规则场景的触发类型枚举
  11 + *
  12 + * 设备触发,定时触发
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotRuleSceneActionTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + DEVICE_CONTROL(1), // 设备执行
  19 + ALERT(2), // 告警执行
  20 + DATA_BRIDGE(3); // 桥接执行
  21 +
  22 + private final Integer type;
  23 +
  24 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new);
  25 +
  26 + @Override
  27 + public Integer[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerConditionParameterOperatorEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.hutool.core.util.ArrayUtil;
  4 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  5 +import lombok.Getter;
  6 +import lombok.RequiredArgsConstructor;
  7 +
  8 +import java.util.Arrays;
  9 +
  10 +/**
  11 + * IoT 场景触发条件参数的操作符枚举
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@RequiredArgsConstructor
  16 +@Getter
  17 +public enum IotRuleSceneTriggerConditionParameterOperatorEnum implements ArrayValuable<String> {
  18 +
  19 + EQUALS("=", "#source == #value"),
  20 + NOT_EQUALS("!=", "!(#source == #value)"),
  21 +
  22 + GREATER_THAN(">", "#source > #value"),
  23 + GREATER_THAN_OR_EQUALS(">=", "#source >= #value"),
  24 +
  25 + LESS_THAN("<", "#source < #value"),
  26 + LESS_THAN_OR_EQUALS("<=", "#source <= #value"),
  27 +
  28 + IN("in", "#values.contains(#source)"),
  29 + NOT_IN("not in", "!(#values.contains(#source))"),
  30 +
  31 + BETWEEN("between", "(#source >= #values.get(0)) && (#source <= #values.get(1))"),
  32 + NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"),
  33 +
  34 + LIKE("like", "#source.contains(#value)"), // 字符串匹配
  35 + NOT_NULL("not null", "#source != null && #source.length() > 0"); // 非空
  36 +
  37 + private final String operator;
  38 + private final String springExpression;
  39 +
  40 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerConditionParameterOperatorEnum::getOperator).toArray(String[]::new);
  41 +
  42 + /**
  43 + * Spring 表达式 - 原始值
  44 + */
  45 + public static final String SPRING_EXPRESSION_SOURCE = "source";
  46 + /**
  47 + * Spring 表达式 - 目标值
  48 + */
  49 + public static final String SPRING_EXPRESSION_VALUE = "value";
  50 + /**
  51 + * Spring 表达式 - 目标值数组
  52 + */
  53 + public static final String SPRING_EXPRESSION_VALUE_List = "values";
  54 +
  55 + public static IotRuleSceneTriggerConditionParameterOperatorEnum operatorOf(String operator) {
  56 + return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values());
  57 + }
  58 +
  59 + @Override
  60 + public String[] array() {
  61 + return ARRAYS;
  62 + }
  63 +
  64 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.rule;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.Getter;
  5 +import lombok.RequiredArgsConstructor;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 场景流转的触发类型枚举
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@RequiredArgsConstructor
  15 +@Getter
  16 +public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable<Integer> {
  17 +
  18 + DEVICE(1), // 设备触发
  19 + TIMER(2); // 定时触发
  20 +
  21 + private final Integer type;
  22 +
  23 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new);
  24 +
  25 + @Override
  26 + public Integer[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 数据定义的数据类型枚举类
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotDataSpecsDataTypeEnum implements ArrayValuable<String> {
  17 +
  18 + INT("int"),
  19 + FLOAT("float"),
  20 + DOUBLE("double"),
  21 + ENUM("enum"),
  22 + BOOL("bool"),
  23 + TEXT("text"),
  24 + DATE("date"),
  25 + STRUCT("struct"),
  26 + ARRAY("array");
  27 +
  28 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotDataSpecsDataTypeEnum::getDataType).toArray(String[]::new);
  29 +
  30 + private final String dataType;
  31 +
  32 + @Override
  33 + public String[] array() {
  34 + return ARRAYS;
  35 + }
  36 +
  37 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotAccessModeEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java
1 -package cn.iocoder.yudao.module.iot.enums.product; 1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
2 2
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
3 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
4 import lombok.Getter; 5 import lombok.Getter;
5 6
  7 +import java.util.Arrays;
  8 +
6 /** 9 /**
7 - * IOT 访问方式枚举类 10 + * IoT 产品物模型属性读取类型枚举
8 * 11 *
9 * @author ahh 12 * @author ahh
10 */ 13 */
11 @AllArgsConstructor 14 @AllArgsConstructor
12 @Getter 15 @Getter
13 -public enum IotAccessModeEnum { 16 +public enum IotThingModelAccessModeEnum implements ArrayValuable<String> {
14 17
15 - READ("r"),  
16 - WRITE("w"), 18 + READ_ONLY("r"),
17 READ_WRITE("rw"); 19 READ_WRITE("rw");
18 20
  21 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelAccessModeEnum::getMode).toArray(String[]::new);
  22 +
19 private final String mode; 23 private final String mode;
20 24
  25 + @Override
  26 + public String[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
21 } 30 }
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +
  10 +/**
  11 + * IoT 产品物模型参数是输入参数还是输出参数枚举
  12 + *
  13 + * @author HUIHUI
  14 + */
  15 +@AllArgsConstructor
  16 +@Getter
  17 +public enum IotThingModelParamDirectionEnum implements ArrayValuable<String> {
  18 +
  19 + INPUT("input"), // 输入参数
  20 + OUTPUT("output"); // 输出参数
  21 +
  22 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelParamDirectionEnum::getDirection).toArray(String[]::new);
  23 +
  24 + private final String direction;
  25 +
  26 + @Override
  27 + public String[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 产品物模型服务调用方式枚举
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotThingModelServiceCallTypeEnum implements ArrayValuable<String> {
  17 +
  18 + ASYNC("async"), // 异步调用
  19 + SYNC("sync"); // 同步调用
  20 +
  21 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceCallTypeEnum::getType).toArray(String[]::new);
  22 +
  23 + private final String type;
  24 +
  25 + @Override
  26 + public String[] array() {
  27 + return ARRAYS;
  28 + }
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
  2 +
  3 +import cn.iocoder.yudao.framework.common.core.ArrayValuable;
  4 +import lombok.AllArgsConstructor;
  5 +import lombok.Getter;
  6 +
  7 +import java.util.Arrays;
  8 +
  9 +/**
  10 + * IoT 产品物模型事件类型枚举
  11 + *
  12 + * @author HUIHUI
  13 + */
  14 +@AllArgsConstructor
  15 +@Getter
  16 +public enum IotThingModelServiceEventTypeEnum implements ArrayValuable<String> {
  17 +
  18 + INFO("info"), // 信息
  19 + ALERT("alert"), // 告警
  20 + ERROR("error"); // 故障
  21 +
  22 + public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceEventTypeEnum::getType).toArray(String[]::new);
  23 +
  24 + private final String type;
  25 +
  26 + @Override
  27 + public String[] array() {
  28 + return ARRAYS;
  29 + }
  30 +
  31 +}
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/product/IotProductFunctionTypeEnum.java renamed to yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelTypeEnum.java
1 -package cn.iocoder.yudao.module.iot.enums.product; 1 +package cn.iocoder.yudao.module.iot.enums.thingmodel;
2 2
3 import cn.iocoder.yudao.framework.common.core.ArrayValuable; 3 import cn.iocoder.yudao.framework.common.core.ArrayValuable;
4 import lombok.AllArgsConstructor; 4 import lombok.AllArgsConstructor;
@@ -7,19 +7,19 @@ import lombok.Getter; @@ -7,19 +7,19 @@ import lombok.Getter;
7 import java.util.Arrays; 7 import java.util.Arrays;
8 8
9 /** 9 /**
10 - * IOT 产品功能(物模型)类型枚举类 10 + * IoT 产品功能(物模型)类型枚举类
11 * 11 *
12 * @author ahh 12 * @author ahh
13 */ 13 */
14 @AllArgsConstructor 14 @AllArgsConstructor
15 @Getter 15 @Getter
16 -public enum IotProductFunctionTypeEnum implements ArrayValuable<Integer> { 16 +public enum IotThingModelTypeEnum implements ArrayValuable<Integer> {
17 17
18 PROPERTY(1, "属性"), 18 PROPERTY(1, "属性"),
19 SERVICE(2, "服务"), 19 SERVICE(2, "服务"),
20 EVENT(3, "事件"); 20 EVENT(3, "事件");
21 21
22 - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotProductFunctionTypeEnum::getType).toArray(Integer[]::new); 22 + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotThingModelTypeEnum::getType).toArray(Integer[]::new);
23 23
24 /** 24 /**
25 * 类型 25 * 类型
yudao-module-iot/yudao-module-iot-biz/pom.xml
@@ -25,6 +25,11 @@ @@ -25,6 +25,11 @@
25 <version>${revision}</version> 25 <version>${revision}</version>
26 </dependency> 26 </dependency>
27 27
  28 + <dependency>
  29 + <groupId>cn.iocoder.boot</groupId>
  30 + <artifactId>yudao-spring-boot-starter-biz-tenant</artifactId>
  31 + </dependency>
  32 +
28 <!-- Web 相关 --> 33 <!-- Web 相关 -->
29 <dependency> 34 <dependency>
30 <groupId>cn.iocoder.boot</groupId> 35 <groupId>cn.iocoder.boot</groupId>
@@ -38,10 +43,20 @@ @@ -38,10 +43,20 @@
38 43
39 <!-- DB 相关 --> 44 <!-- DB 相关 -->
40 <dependency> 45 <dependency>
  46 + <groupId>com.taosdata.jdbc</groupId>
  47 + <artifactId>taos-jdbcdriver</artifactId>
  48 + </dependency>
  49 +
  50 + <dependency>
41 <groupId>cn.iocoder.boot</groupId> 51 <groupId>cn.iocoder.boot</groupId>
42 <artifactId>yudao-spring-boot-starter-mybatis</artifactId> 52 <artifactId>yudao-spring-boot-starter-mybatis</artifactId>
43 </dependency> 53 </dependency>
44 54
  55 + <dependency>
  56 + <groupId>cn.iocoder.boot</groupId>
  57 + <artifactId>yudao-spring-boot-starter-redis</artifactId>
  58 + </dependency>
  59 +
45 <!-- Test 测试相关 --> 60 <!-- Test 测试相关 -->
46 <dependency> 61 <dependency>
47 <groupId>cn.iocoder.boot</groupId> 62 <groupId>cn.iocoder.boot</groupId>
@@ -54,11 +69,64 @@ @@ -54,11 +69,64 @@
54 <artifactId>yudao-spring-boot-starter-excel</artifactId> 69 <artifactId>yudao-spring-boot-starter-excel</artifactId>
55 </dependency> 70 </dependency>
56 71
57 - <!-- MQTT --> 72 + <!-- 消息队列相关 -->
  73 + <dependency>
  74 + <groupId>org.apache.rocketmq</groupId>
  75 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  76 + <optional>true</optional>
  77 + </dependency>
  78 + <dependency>
  79 + <groupId>org.springframework.kafka</groupId>
  80 + <artifactId>spring-kafka</artifactId>
  81 + <optional>true</optional>
  82 + </dependency>
  83 + <dependency>
  84 + <groupId>org.springframework.boot</groupId>
  85 + <artifactId>spring-boot-starter-amqp</artifactId>
  86 + <optional>true</optional>
  87 + </dependency>
  88 +
  89 + <dependency>
  90 + <groupId>org.pf4j</groupId> <!-- PF4J:内置插件机制 -->
  91 + <artifactId>pf4j-spring</artifactId>
  92 + </dependency>
  93 +
  94 + <!-- TODO @芋艿:bom 管理 -->
58 <dependency> 95 <dependency>
59 - <groupId>org.eclipse.paho</groupId>  
60 - <artifactId>org.eclipse.paho.client.mqttv3</artifactId> 96 + <groupId>org.apache.groovy</groupId>
  97 + <artifactId>groovy-all</artifactId>
  98 + <version>4.0.25</version>
  99 + <type>pom</type>
61 </dependency> 100 </dependency>
  101 +
  102 + <!-- TODO @芋艿:bom 管理 -->
  103 + <dependency>
  104 + <groupId>org.graalvm.js</groupId>
  105 + <artifactId>js</artifactId>
  106 + <version>24.1.2</version>
  107 + <type>pom</type>
  108 + </dependency>
  109 + <dependency>
  110 + <groupId>org.graalvm.js</groupId>
  111 + <artifactId>js-scriptengine</artifactId>
  112 + <version>24.1.2</version>
  113 + </dependency>
  114 +
  115 + <!-- TODO @芋艿:合理注释 -->
  116 + <!-- IoT 数据桥梁的执行器所需消息队列。如果您只需要使用 rocketmq 那么则注释掉其它消息队列即可 -->
  117 + <!-- <dependency>-->
  118 + <!-- <groupId>org.apache.rocketmq</groupId>-->
  119 + <!-- <artifactId>rocketmq-spring-boot-starter</artifactId>-->
  120 + <!-- </dependency>-->
  121 + <!-- <dependency>-->
  122 + <!-- <groupId>org.springframework.kafka</groupId>-->
  123 + <!-- <artifactId>spring-kafka</artifactId>-->
  124 + <!-- </dependency>-->
  125 + <!-- <dependency>-->
  126 + <!-- <groupId>org.springframework.boot</groupId>-->
  127 + <!-- <artifactId>spring-boot-starter-amqp</artifactId>-->
  128 + <!-- </dependency>-->
  129 +
62 </dependencies> 130 </dependencies>
63 131
64 </project> 132 </project>
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/ScriptTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot;
  2 +
  3 +import cn.hutool.script.ScriptUtil;
  4 +import javax.script.Bindings;
  5 +import javax.script.ScriptEngine;
  6 +import javax.script.ScriptException;
  7 +
  8 +/**
  9 + * TODO 芋艿:测试脚本的接入
  10 + */
  11 +public class ScriptTest {
  12 +
  13 + public static void main2(String[] args) {
  14 + // 创建一个 Groovy 脚本引擎
  15 + ScriptEngine engine = ScriptUtil.createGroovyEngine();
  16 +
  17 + // 创建绑定参数
  18 + Bindings bindings = engine.createBindings();
  19 + bindings.put("name", "Alice");
  20 + bindings.put("age", 30);
  21 +
  22 + // 定义一个稍微复杂的 Groovy 脚本
  23 + String script = "def greeting = 'Hello, ' + name + '!';\n" +
  24 + "def ageInFiveYears = age + 5;\n" +
  25 + "def message = greeting + ' In five years, you will be ' + ageInFiveYears + ' years old.';\n" +
  26 + "return message.toUpperCase();\n";
  27 +
  28 + try {
  29 + // 执行脚本并获取结果
  30 + Object result = engine.eval(script, bindings);
  31 + System.out.println(result); // 输出: HELLO, ALICE! IN FIVE YEARS, YOU WILL BE 35 YEARS OLD.
  32 + } catch (ScriptException e) {
  33 + e.printStackTrace();
  34 + }
  35 + }
  36 +
  37 + public static void main(String[] args) {
  38 + // 创建一个 JavaScript 脚本引擎
  39 + ScriptEngine jsEngine = ScriptUtil.createJsEngine();
  40 +
  41 + // 创建绑定参数
  42 + Bindings jsBindings = jsEngine.createBindings();
  43 + jsBindings.put("name", "Bob");
  44 + jsBindings.put("age", 25);
  45 +
  46 + // 定义一个简单的 JavaScript 脚本
  47 + String jsScript = "var greeting = 'Hello, ' + name + '!';\n" +
  48 + "var ageInTenYears = age + 10;\n" +
  49 + "var message = greeting + ' In ten years, you will be ' + ageInTenYears + ' years old.';\n" +
  50 + "message.toUpperCase();\n";
  51 +
  52 + try {
  53 + // 执行脚本并获取结果
  54 + Object jsResult = jsEngine.eval(jsScript, jsBindings);
  55 + System.out.println(jsResult); // 输出: HELLO, BOB! IN TEN YEARS, YOU WILL BE 35 YEARS OLD.
  56 + } catch (ScriptException e) {
  57 + e.printStackTrace();
  58 + }
  59 + }
  60 +
  61 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceUpstreamApiImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.api.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
  5 +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
  6 +import cn.iocoder.yudao.module.iot.service.plugin.IotPluginInstanceService;
  7 +import jakarta.annotation.Resource;
  8 +import org.springframework.validation.annotation.Validated;
  9 +import org.springframework.web.bind.annotation.RestController;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  12 +
  13 +/**
  14 + * * 设备数据 Upstream 上行 API 实现类
  15 + */
  16 +@RestController
  17 +@Validated
  18 +public class IoTDeviceUpstreamApiImpl implements IotDeviceUpstreamApi {
  19 +
  20 + @Resource
  21 + private IotDeviceUpstreamService deviceUpstreamService;
  22 + @Resource
  23 + private IotPluginInstanceService pluginInstanceService;
  24 +
  25 + // ========== 设备相关 ==========
  26 +
  27 + @Override
  28 + public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
  29 + deviceUpstreamService.updateDeviceState(updateReqDTO);
  30 + return success(true);
  31 + }
  32 +
  33 + @Override
  34 + public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
  35 + deviceUpstreamService.reportDeviceProperty(reportReqDTO);
  36 + return success(true);
  37 + }
  38 +
  39 + @Override
  40 + public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
  41 + deviceUpstreamService.reportDeviceEvent(reportReqDTO);
  42 + return success(true);
  43 + }
  44 +
  45 + @Override
  46 + public CommonResult<Boolean> registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
  47 + deviceUpstreamService.registerDevice(registerReqDTO);
  48 + return success(true);
  49 + }
  50 +
  51 + @Override
  52 + public CommonResult<Boolean> registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
  53 + deviceUpstreamService.registerSubDevice(registerReqDTO);
  54 + return success(true);
  55 + }
  56 +
  57 + @Override
  58 + public CommonResult<Boolean> addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) {
  59 + deviceUpstreamService.addDeviceTopology(addReqDTO);
  60 + return success(true);
  61 + }
  62 +
  63 + @Override
  64 + public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
  65 + boolean result = deviceUpstreamService.authenticateEmqxConnection(authReqDTO);
  66 + return success(result);
  67 + }
  68 +
  69 + // ========== 插件相关 ==========
  70 +
  71 + @Override
  72 + public CommonResult<Boolean> heartbeatPluginInstance(IotPluginInstanceHeartbeatReqDTO heartbeatReqDTO) {
  73 + pluginInstanceService.heartbeatPluginInstance(heartbeatReqDTO);
  74 + return success(true);
  75 + }
  76 +
  77 +}
0 \ No newline at end of file 78 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/package-info.java 0 → 100644
  1 +/**
  2 + * 占位
  3 + *
  4 + * TODO 芋艿:后续删除
  5 + */
  6 +package cn.iocoder.yudao.module.iot.api;
0 \ No newline at end of file 7 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.http 0 → 100644
  1 +### 请求 /iot/device/downstream 接口(服务调用) => 成功
  2 +POST {{baseUrl}}/iot/device/downstream
  3 +Content-Type: application/json
  4 +tenant-id: {{adminTenentId}}
  5 +Authorization: Bearer {{token}}
  6 +
  7 +{
  8 + "id": 25,
  9 + "type": "service",
  10 + "identifier": "temperature",
  11 + "data": {
  12 + "xx": "yy"
  13 + }
  14 +}
  15 +
  16 +### 请求 /iot/device/downstream 接口(属性设置) => 成功
  17 +POST {{baseUrl}}/iot/device/downstream
  18 +Content-Type: application/json
  19 +tenant-id: {{adminTenentId}}
  20 +Authorization: Bearer {{token}}
  21 +
  22 +{
  23 + "id": 25,
  24 + "type": "property",
  25 + "identifier": "set",
  26 + "data": {
  27 + "xx": "yy"
  28 + }
  29 +}
  30 +
  31 +### 请求 /iot/device/downstream 接口(属性获取) => 成功
  32 +POST {{baseUrl}}/iot/device/downstream
  33 +Content-Type: application/json
  34 +tenant-id: {{adminTenentId}}
  35 +Authorization: Bearer {{token}}
  36 +
  37 +{
  38 + "id": 25,
  39 + "type": "property",
  40 + "identifier": "get",
  41 + "data": ["xx", "yy"]
  42 +}
  43 +
  44 +### 请求 /iot/device/downstream 接口(配置设置) => 成功
  45 +POST {{baseUrl}}/iot/device/downstream
  46 +Content-Type: application/json
  47 +tenant-id: {{adminTenentId}}
  48 +Authorization: Bearer {{token}}
  49 +
  50 +{
  51 + "id": 25,
  52 + "type": "config",
  53 + "identifier": "set"
  54 +}
  55 +
  56 +### 请求 /iot/device/downstream 接口(OTA 升级) => 成功
  57 +POST {{baseUrl}}/iot/device/downstream
  58 +Content-Type: application/json
  59 +tenant-id: {{adminTenentId}}
  60 +Authorization: Bearer {{token}}
  61 +
  62 +{
  63 + "id": 25,
  64 + "type": "ota",
  65 + "identifier": "upgrade",
  66 + "data": {
  67 + "firmwareId": 1,
  68 + "version": "1.0.0",
  69 + "signMethod": "MD5",
  70 + "fileSign": "d41d8cd98f00b204e9800998ecf8427e",
  71 + "fileSize": 1024,
  72 + "fileUrl": "http://example.com/firmware.bin",
  73 + "information": "{\"desc\":\"升级到最新版本\"}"
  74 + }
  75 +}
0 \ No newline at end of file 76 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
1 package cn.iocoder.yudao.module.iot.controller.admin.device; 1 package cn.iocoder.yudao.module.iot.controller.admin.device;
2 2
  3 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;  
7 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;  
8 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;  
9 -import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO; 8 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceDownstreamReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.control.IotDeviceUpstreamReqVO;
  11 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.*;
10 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; 12 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
11 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; 13 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  14 +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceDownstreamService;
  15 +import cn.iocoder.yudao.module.iot.service.device.control.IotDeviceUpstreamService;
12 import io.swagger.v3.oas.annotations.Operation; 16 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.Parameter; 17 import io.swagger.v3.oas.annotations.Parameter;
14 import io.swagger.v3.oas.annotations.tags.Tag; 18 import io.swagger.v3.oas.annotations.tags.Tag;
15 import jakarta.annotation.Resource; 19 import jakarta.annotation.Resource;
  20 +import jakarta.servlet.http.HttpServletResponse;
16 import jakarta.validation.Valid; 21 import jakarta.validation.Valid;
17 import org.springframework.security.access.prepost.PreAuthorize; 22 import org.springframework.security.access.prepost.PreAuthorize;
18 import org.springframework.validation.annotation.Validated; 23 import org.springframework.validation.annotation.Validated;
19 import org.springframework.web.bind.annotation.*; 24 import org.springframework.web.bind.annotation.*;
  25 +import org.springframework.web.multipart.MultipartFile;
20 26
  27 +import java.io.IOException;
  28 +import java.util.Arrays;
  29 +import java.util.Collection;
  30 +import java.util.List;
  31 +
  32 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
21 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 33 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 35
23 @Tag(name = "管理后台 - IoT 设备") 36 @Tag(name = "管理后台 - IoT 设备")
24 @RestController 37 @RestController
@@ -28,6 +41,10 @@ public class IotDeviceController { @@ -28,6 +41,10 @@ public class IotDeviceController {
28 41
29 @Resource 42 @Resource
30 private IotDeviceService deviceService; 43 private IotDeviceService deviceService;
  44 + @Resource
  45 + private IotDeviceUpstreamService deviceUpstreamService;
  46 + @Resource
  47 + private IotDeviceDownstreamService deviceDownstreamService;
31 48
32 @PostMapping("/create") 49 @PostMapping("/create")
33 @Operation(summary = "创建设备") 50 @Operation(summary = "创建设备")
@@ -36,14 +53,6 @@ public class IotDeviceController { @@ -36,14 +53,6 @@ public class IotDeviceController {
36 return success(deviceService.createDevice(createReqVO)); 53 return success(deviceService.createDevice(createReqVO));
37 } 54 }
38 55
39 - @PutMapping("/update-status")  
40 - @Operation(summary = "更新设备状态")  
41 - @PreAuthorize("@ss.hasPermission('iot:device:update')")  
42 - public CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqVO updateReqVO) {  
43 - deviceService.updateDeviceStatus(updateReqVO);  
44 - return success(true);  
45 - }  
46 -  
47 @PutMapping("/update") 56 @PutMapping("/update")
48 @Operation(summary = "更新设备") 57 @Operation(summary = "更新设备")
49 @PreAuthorize("@ss.hasPermission('iot:device:update')") 58 @PreAuthorize("@ss.hasPermission('iot:device:update')")
@@ -52,8 +61,18 @@ public class IotDeviceController { @@ -52,8 +61,18 @@ public class IotDeviceController {
52 return success(true); 61 return success(true);
53 } 62 }
54 63
  64 + // TODO @芋艿:参考阿里云:1)绑定网关;2)解绑网关
  65 +
  66 + @PutMapping("/update-group")
  67 + @Operation(summary = "更新设备分组")
  68 + @PreAuthorize("@ss.hasPermission('iot:device:update')")
  69 + public CommonResult<Boolean> updateDeviceGroup(@Valid @RequestBody IotDeviceUpdateGroupReqVO updateReqVO) {
  70 + deviceService.updateDeviceGroup(updateReqVO);
  71 + return success(true);
  72 + }
  73 +
55 @DeleteMapping("/delete") 74 @DeleteMapping("/delete")
56 - @Operation(summary = "删除设备") 75 + @Operation(summary = "删除单个设备")
57 @Parameter(name = "id", description = "编号", required = true) 76 @Parameter(name = "id", description = "编号", required = true)
58 @PreAuthorize("@ss.hasPermission('iot:device:delete')") 77 @PreAuthorize("@ss.hasPermission('iot:device:delete')")
59 public CommonResult<Boolean> deleteDevice(@RequestParam("id") Long id) { 78 public CommonResult<Boolean> deleteDevice(@RequestParam("id") Long id) {
@@ -61,6 +80,15 @@ public class IotDeviceController { @@ -61,6 +80,15 @@ public class IotDeviceController {
61 return success(true); 80 return success(true);
62 } 81 }
63 82
  83 + @DeleteMapping("/delete-list")
  84 + @Operation(summary = "删除多个设备")
  85 + @Parameter(name = "ids", description = "编号数组", required = true)
  86 + @PreAuthorize("@ss.hasPermission('iot:device:delete')")
  87 + public CommonResult<Boolean> deleteDeviceList(@RequestParam("ids") Collection<Long> ids) {
  88 + deviceService.deleteDeviceList(ids);
  89 + return success(true);
  90 + }
  91 +
64 @GetMapping("/get") 92 @GetMapping("/get")
65 @Operation(summary = "获得设备") 93 @Operation(summary = "获得设备")
66 @Parameter(name = "id", description = "编号", required = true, example = "1024") 94 @Parameter(name = "id", description = "编号", required = true, example = "1024")
@@ -78,6 +106,19 @@ public class IotDeviceController { @@ -78,6 +106,19 @@ public class IotDeviceController {
78 return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class)); 106 return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class));
79 } 107 }
80 108
  109 + @GetMapping("/export-excel")
  110 + @Operation(summary = "导出设备 Excel")
  111 + @PreAuthorize("@ss.hasPermission('iot:device:export')")
  112 + @ApiAccessLog(operateType = EXPORT)
  113 + public void exportDeviceExcel(@Valid IotDevicePageReqVO exportReqVO,
  114 + HttpServletResponse response) throws IOException {
  115 + exportReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  116 + CommonResult<PageResult<IotDeviceRespVO>> result = getDevicePage(exportReqVO);
  117 + // 导出 Excel
  118 + ExcelUtils.write(response, "设备.xls", "数据", IotDeviceRespVO.class,
  119 + result.getData().getList());
  120 + }
  121 +
81 @GetMapping("/count") 122 @GetMapping("/count")
82 @Operation(summary = "获得设备数量") 123 @Operation(summary = "获得设备数量")
83 @Parameter(name = "productId", description = "产品编号", example = "1") 124 @Parameter(name = "productId", description = "产品编号", example = "1")
@@ -86,4 +127,62 @@ public class IotDeviceController { @@ -86,4 +127,62 @@ public class IotDeviceController {
86 return success(deviceService.getDeviceCountByProductId(productId)); 127 return success(deviceService.getDeviceCountByProductId(productId));
87 } 128 }
88 129
  130 + @GetMapping("/simple-list")
  131 + @Operation(summary = "获取设备的精简信息列表", description = "主要用于前端的下拉选项")
  132 + @Parameter(name = "deviceType", description = "设备类型", example = "1")
  133 + public CommonResult<List<IotDeviceRespVO>> getSimpleDeviceList(
  134 + @RequestParam(value = "deviceType", required = false) Integer deviceType) {
  135 + List<IotDeviceDO> list = deviceService.getDeviceListByDeviceType(deviceType);
  136 + return success(convertList(list, device -> // 只返回 id、name 字段
  137 + new IotDeviceRespVO().setId(device.getId()).setDeviceName(device.getDeviceName())));
  138 + }
  139 +
  140 + @PostMapping("/import")
  141 + @Operation(summary = "导入设备")
  142 + @PreAuthorize("@ss.hasPermission('iot:device:import')")
  143 + public CommonResult<IotDeviceImportRespVO> importDevice(
  144 + @RequestParam("file") MultipartFile file,
  145 + @RequestParam(value = "updateSupport", required = false, defaultValue = "false") Boolean updateSupport)
  146 + throws Exception {
  147 + List<IotDeviceImportExcelVO> list = ExcelUtils.read(file, IotDeviceImportExcelVO.class);
  148 + return success(deviceService.importDevice(list, updateSupport));
  149 + }
  150 +
  151 + @GetMapping("/get-import-template")
  152 + @Operation(summary = "获得导入设备模板")
  153 + public void importTemplate(HttpServletResponse response) throws IOException {
  154 + // 手动创建导出 demo
  155 + List<IotDeviceImportExcelVO> list = Arrays.asList(
  156 + IotDeviceImportExcelVO.builder().deviceName("温度传感器001").parentDeviceName("gateway110")
  157 + .productKey("1de24640dfe").groupNames("灰度分组,生产分组").build(),
  158 + IotDeviceImportExcelVO.builder().deviceName("biubiu")
  159 + .productKey("YzvHxd4r67sT4s2B").groupNames("").build());
  160 + // 输出
  161 + ExcelUtils.write(response, "设备导入模板.xls", "数据", IotDeviceImportExcelVO.class, list);
  162 + }
  163 +
  164 + @PostMapping("/upstream")
  165 + @Operation(summary = "设备上行", description = "可用于设备模拟")
  166 + @PreAuthorize("@ss.hasPermission('iot:device:upstream')")
  167 + public CommonResult<Boolean> upstreamDevice(@Valid @RequestBody IotDeviceUpstreamReqVO upstreamReqVO) {
  168 + deviceUpstreamService.upstreamDevice(upstreamReqVO);
  169 + return success(true);
  170 + }
  171 +
  172 + @PostMapping("/downstream")
  173 + @Operation(summary = "设备下行", description = "可用于设备模拟")
  174 + @PreAuthorize("@ss.hasPermission('iot:device:downstream')")
  175 + public CommonResult<Boolean> downstreamDevice(@Valid @RequestBody IotDeviceDownstreamReqVO downstreamReqVO) {
  176 + deviceDownstreamService.downstreamDevice(downstreamReqVO);
  177 + return success(true);
  178 + }
  179 +
  180 + // TODO @haohao:是不是默认详情接口,不返回 secret,然后这个接口,用于统一返回。然后接口名可以更通用一点。
  181 + @GetMapping("/mqtt-connection-params")
  182 + @Operation(summary = "获取 MQTT 连接参数")
  183 + @PreAuthorize("@ss.hasPermission('iot:device:mqtt-connection-params')")
  184 + public CommonResult<IotDeviceMqttConnectionParamsRespVO> getMqttConnectionParams(@RequestParam("deviceId") Long deviceId) {
  185 + return success(deviceService.getMqttConnectionParams(deviceId));
  186 + }
  187 +
89 } 188 }
90 \ No newline at end of file 189 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupRespVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
  11 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceGroupService;
  12 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  13 +import io.swagger.v3.oas.annotations.Operation;
  14 +import io.swagger.v3.oas.annotations.Parameter;
  15 +import io.swagger.v3.oas.annotations.tags.Tag;
  16 +import jakarta.annotation.Resource;
  17 +import jakarta.validation.Valid;
  18 +import org.springframework.security.access.prepost.PreAuthorize;
  19 +import org.springframework.validation.annotation.Validated;
  20 +import org.springframework.web.bind.annotation.*;
  21 +
  22 +import java.util.List;
  23 +
  24 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  25 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  26 +
  27 +@Tag(name = "管理后台 - IoT 设备分组")
  28 +@RestController
  29 +@RequestMapping("/iot/device-group")
  30 +@Validated
  31 +public class IotDeviceGroupController {
  32 +
  33 + @Resource
  34 + private IotDeviceGroupService deviceGroupService;
  35 + @Resource
  36 + private IotDeviceService deviceService;
  37 +
  38 + @PostMapping("/create")
  39 + @Operation(summary = "创建设备分组")
  40 + @PreAuthorize("@ss.hasPermission('iot:device-group:create')")
  41 + public CommonResult<Long> createDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO createReqVO) {
  42 + return success(deviceGroupService.createDeviceGroup(createReqVO));
  43 + }
  44 +
  45 + @PutMapping("/update")
  46 + @Operation(summary = "更新设备分组")
  47 + @PreAuthorize("@ss.hasPermission('iot:device-group:update')")
  48 + public CommonResult<Boolean> updateDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO updateReqVO) {
  49 + deviceGroupService.updateDeviceGroup(updateReqVO);
  50 + return success(true);
  51 + }
  52 +
  53 + @DeleteMapping("/delete")
  54 + @Operation(summary = "删除设备分组")
  55 + @Parameter(name = "id", description = "编号", required = true)
  56 + @PreAuthorize("@ss.hasPermission('iot:device-group:delete')")
  57 + public CommonResult<Boolean> deleteDeviceGroup(@RequestParam("id") Long id) {
  58 + deviceGroupService.deleteDeviceGroup(id);
  59 + return success(true);
  60 + }
  61 +
  62 + @GetMapping("/get")
  63 + @Operation(summary = "获得设备分组")
  64 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  65 + @PreAuthorize("@ss.hasPermission('iot:device-group:query')")
  66 + public CommonResult<IotDeviceGroupRespVO> getDeviceGroup(@RequestParam("id") Long id) {
  67 + IotDeviceGroupDO deviceGroup = deviceGroupService.getDeviceGroup(id);
  68 + return success(BeanUtils.toBean(deviceGroup, IotDeviceGroupRespVO.class));
  69 + }
  70 +
  71 + @GetMapping("/page")
  72 + @Operation(summary = "获得设备分组分页")
  73 + @PreAuthorize("@ss.hasPermission('iot:device-group:query')")
  74 + public CommonResult<PageResult<IotDeviceGroupRespVO>> getDeviceGroupPage(@Valid IotDeviceGroupPageReqVO pageReqVO) {
  75 + PageResult<IotDeviceGroupDO> pageResult = deviceGroupService.getDeviceGroupPage(pageReqVO);
  76 + return success(BeanUtils.toBean(pageResult, IotDeviceGroupRespVO.class,
  77 + group -> group.setDeviceCount(deviceService.getDeviceCountByGroupId(group.getId()))));
  78 + }
  79 +
  80 + @GetMapping("/simple-list")
  81 + @Operation(summary = "获取设备分组的精简信息列表", description = "只包含被开启的分组,主要用于前端的下拉选项")
  82 + public CommonResult<List<IotDeviceGroupRespVO>> getSimpleDeviceGroupList() {
  83 + List<IotDeviceGroupDO> list = deviceGroupService.getDeviceGroupListByStatus(CommonStatusEnum.ENABLE.getStatus());
  84 + return success(convertList(list, group -> // 只返回 id、name 字段
  85 + new IotDeviceGroupRespVO().setId(group.getId()).setName(group.getName())));
  86 + }
  87 +
  88 +}
0 \ No newline at end of file 89 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceLogController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDeviceLogRespVO;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceLogDO;
  9 +import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.tags.Tag;
  12 +import jakarta.annotation.Resource;
  13 +import jakarta.validation.Valid;
  14 +import org.springframework.security.access.prepost.PreAuthorize;
  15 +import org.springframework.validation.annotation.Validated;
  16 +import org.springframework.web.bind.annotation.GetMapping;
  17 +import org.springframework.web.bind.annotation.RequestMapping;
  18 +import org.springframework.web.bind.annotation.RestController;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - IoT 设备日志")
  23 +@RestController
  24 +@RequestMapping("/iot/device/log")
  25 +@Validated
  26 +public class IotDeviceLogController {
  27 +
  28 + @Resource
  29 + private IotDeviceLogService deviceLogService;
  30 +
  31 + @GetMapping("/page")
  32 + @Operation(summary = "获得设备日志分页")
  33 + @PreAuthorize("@ss.hasPermission('iot:device:log-query')")
  34 + public CommonResult<PageResult<IotDeviceLogRespVO>> getDeviceLogPage(@Valid IotDeviceLogPageReqVO pageReqVO) {
  35 + PageResult<IotDeviceLogDO> pageResult = deviceLogService.getDeviceLogPage(pageReqVO);
  36 + return success(BeanUtils.toBean(pageResult, IotDeviceLogRespVO.class));
  37 + }
  38 +
  39 +}
0 \ No newline at end of file 40 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDevicePropertyController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.date.LocalDateTimeUtil;
  5 +import cn.hutool.core.lang.Assert;
  6 +import cn.hutool.core.util.StrUtil;
  7 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  8 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyHistoryPageReqVO;
  10 +import cn.iocoder.yudao.module.iot.controller.admin.device.vo.data.IotDevicePropertyRespVO;
  11 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
  12 +import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
  13 +import cn.iocoder.yudao.module.iot.dal.dataobject.thingmodel.IotThingModelDO;
  14 +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
  15 +import cn.iocoder.yudao.module.iot.service.device.data.IotDevicePropertyService;
  16 +import cn.iocoder.yudao.module.iot.service.thingmodel.IotThingModelService;
  17 +import io.swagger.v3.oas.annotations.Operation;
  18 +import io.swagger.v3.oas.annotations.Parameter;
  19 +import io.swagger.v3.oas.annotations.Parameters;
  20 +import io.swagger.v3.oas.annotations.tags.Tag;
  21 +import jakarta.annotation.Resource;
  22 +import jakarta.validation.Valid;
  23 +import org.springframework.security.access.prepost.PreAuthorize;
  24 +import org.springframework.validation.annotation.Validated;
  25 +import org.springframework.web.bind.annotation.GetMapping;
  26 +import org.springframework.web.bind.annotation.RequestMapping;
  27 +import org.springframework.web.bind.annotation.RequestParam;
  28 +import org.springframework.web.bind.annotation.RestController;
  29 +
  30 +import java.util.List;
  31 +import java.util.Map;
  32 +
  33 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  35 +
  36 +@Tag(name = "管理后台 - IoT 设备属性")
  37 +@RestController
  38 +@RequestMapping("/iot/device/property")
  39 +@Validated
  40 +public class IotDevicePropertyController {
  41 +
  42 + @Resource
  43 + private IotDevicePropertyService devicePropertyService;
  44 + @Resource
  45 + private IotThingModelService thingModelService;
  46 + @Resource
  47 + private IotDeviceService deviceService;
  48 +
  49 + @GetMapping("/latest")
  50 + @Operation(summary = "获取设备属性最新属性")
  51 + @Parameters({
  52 + @Parameter(name = "deviceId", description = "设备编号", required = true),
  53 + @Parameter(name = "identifier", description = "标识符"),
  54 + @Parameter(name = "name", description = "名称")
  55 + })
  56 + @PreAuthorize("@ss.hasPermission('iot:device:property-query')")
  57 + public CommonResult<List<IotDevicePropertyRespVO>> getLatestDeviceProperties(
  58 + @RequestParam("deviceId") Long deviceId,
  59 + @RequestParam(value = "identifier", required = false) String identifier,
  60 + @RequestParam(value = "name", required = false) String name) {
  61 + Map<String, IotDevicePropertyDO> properties = devicePropertyService.getLatestDeviceProperties(deviceId);
  62 +
  63 + // 拼接数据
  64 + IotDeviceDO device = deviceService.getDevice(deviceId);
  65 + Assert.notNull(device, "设备不存在");
  66 + List<IotThingModelDO> thingModels = thingModelService.getThingModelListByProductId(device.getProductId());
  67 + return success(convertList(properties.entrySet(), entry -> {
  68 + IotThingModelDO thingModel = CollUtil.findOne(thingModels,
  69 + item -> item.getIdentifier().equals(entry.getKey()));
  70 + if (thingModel == null || thingModel.getProperty() == null) {
  71 + return null;
  72 + }
  73 + if (StrUtil.isNotEmpty(identifier) && !StrUtil.contains(thingModel.getIdentifier(), identifier)) {
  74 + return null;
  75 + }
  76 + if (StrUtil.isNotEmpty(name) && !StrUtil.contains(thingModel.getName(), name)) {
  77 + return null;
  78 + }
  79 + // 构建对象
  80 + IotDevicePropertyDO property = entry.getValue();
  81 + return new IotDevicePropertyRespVO().setProperty(thingModel.getProperty())
  82 + .setValue(property.getValue()).setUpdateTime(LocalDateTimeUtil.toEpochMilli(property.getUpdateTime()));
  83 + }));
  84 + }
  85 +
  86 + @GetMapping("/history-page")
  87 + @Operation(summary = "获取设备属性历史数据")
  88 + @PreAuthorize("@ss.hasPermission('iot:device:property-query')")
  89 + public CommonResult<PageResult<IotDevicePropertyRespVO>> getHistoryDevicePropertyPage(
  90 + @Valid IotDevicePropertyHistoryPageReqVO pageReqVO) {
  91 + Assert.notEmpty(pageReqVO.getIdentifier(), "标识符不能为空");
  92 + return success(devicePropertyService.getHistoryDevicePropertyPage(pageReqVO));
  93 + }
  94 +
  95 +}
0 \ No newline at end of file 96 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java deleted
1 -package cn.iocoder.yudao.module.iot.controller.admin.device.vo;  
2 -  
3 -import cn.iocoder.yudao.framework.common.pojo.PageParam;  
4 -import cn.iocoder.yudao.framework.common.validation.InEnum;  
5 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;  
6 -import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;  
7 -import io.swagger.v3.oas.annotations.media.Schema;  
8 -import lombok.Data;  
9 -import lombok.EqualsAndHashCode;  
10 -import lombok.ToString;  
11 -import org.springframework.format.annotation.DateTimeFormat;  
12 -  
13 -import java.math.BigDecimal;  
14 -import java.time.LocalDateTime;  
15 -  
16 -import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;  
17 -  
18 -@Schema(description = "管理后台 - IoT 设备分页 Request VO")  
19 -@Data  
20 -@EqualsAndHashCode(callSuper = true)  
21 -@ToString(callSuper = true)  
22 -public class IotDevicePageReqVO extends PageParam {  
23 -  
24 - // TODO @芋艿:需要去掉一些多余的字段;  
25 -  
26 - @Schema(description = "设备唯一标识符", example = "24602")  
27 - private String deviceKey;  
28 -  
29 - @Schema(description = "设备名称", example = "王五")  
30 - private String deviceName;  
31 -  
32 - @Schema(description = "备注名称", example = "张三")  
33 - private String nickname;  
34 -  
35 - @Schema(description = "产品编号", example = "26202")  
36 - private Long productId;  
37 -  
38 - @Schema(description = "产品标识")  
39 - private String productKey;  
40 -  
41 - @Schema(description = "设备类型", example = "1")  
42 - @InEnum(IotProductDeviceTypeEnum.class)  
43 - private Integer deviceType;  
44 -  
45 - @Schema(description = "网关设备 ID", example = "16380")  
46 - private Long gatewayId;  
47 -  
48 - @Schema(description = "设备状态", example = "1")  
49 - @InEnum(IotDeviceStatusEnum.class)  
50 - private Integer status;  
51 -  
52 - @Schema(description = "设备状态最后更新时间")  
53 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
54 - private LocalDateTime[] statusLastUpdateTime;  
55 -  
56 - @Schema(description = "最后上线时间")  
57 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
58 - private LocalDateTime[] lastOnlineTime;  
59 -  
60 - @Schema(description = "最后离线时间")  
61 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
62 - private LocalDateTime[] lastOfflineTime;  
63 -  
64 - @Schema(description = "设备激活时间")  
65 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
66 - private LocalDateTime[] activeTime;  
67 -  
68 - @Schema(description = "设备密钥,用于设备认证,需安全存储")  
69 - private String deviceSecret;  
70 -  
71 - @Schema(description = "MQTT 客户端 ID", example = "24602")  
72 - private String mqttClientId;  
73 -  
74 - @Schema(description = "MQTT 用户名", example = "芋艿")  
75 - private String mqttUsername;  
76 -  
77 - @Schema(description = "MQTT 密码")  
78 - private String mqttPassword;  
79 -  
80 - @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")  
81 - private String authType;  
82 -  
83 - @Schema(description = "创建时间")  
84 - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)  
85 - private LocalDateTime[] createTime;  
86 -  
87 -}  
88 \ No newline at end of file 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java deleted
1 -package cn.iocoder.yudao.module.iot.controller.admin.device.vo;  
2 -  
3 -import cn.iocoder.yudao.framework.common.validation.InEnum;  
4 -import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;  
5 -import io.swagger.v3.oas.annotations.media.Schema;  
6 -import jakarta.validation.constraints.NotNull;  
7 -import lombok.Data;  
8 -  
9 -@Schema(description = "管理后台 - IoT 设备状态更新 Request VO")  
10 -@Data  
11 -public class IotDeviceStatusUpdateReqVO {  
12 -  
13 - @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
14 - @NotNull(message = "设备编号不能为空")  
15 - private Long id;  
16 -  
17 - @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")  
18 - @NotNull(message = "设备状态不能为空")  
19 - @InEnum(IotDeviceStatusEnum.class)  
20 - private Integer status;  
21 -}  
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceDownstreamReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotEmpty;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备下行 Request VO") // 服务调用、属性设置、属性获取等
  11 +@Data
  12 +public class IotDeviceDownstreamReqVO {
  13 +
  14 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  15 + @NotNull(message = "设备编号不能为空")
  16 + private Long id;
  17 +
  18 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
  19 + @NotEmpty(message = "消息类型不能为空")
  20 + @InEnum(IotDeviceMessageTypeEnum.class)
  21 + private String type;
  22 +
  23 + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
  24 + @NotEmpty(message = "标识符不能为空")
  25 + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
  26 +
  27 + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private Object data; // 例如说:服务调用的 params、属性设置的 properties
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/control/IotDeviceUpstreamReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.control;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceMessageTypeEnum;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import jakarta.validation.constraints.NotEmpty;
  7 +import jakarta.validation.constraints.NotNull;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备上行 Request VO") // 属性上报、事件上报、状态变更等
  11 +@Data
  12 +public class IotDeviceUpstreamReqVO {
  13 +
  14 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  15 + @NotNull(message = "设备编号不能为空")
  16 + private Long id;
  17 +
  18 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
  19 + @NotEmpty(message = "消息类型不能为空")
  20 + @InEnum(IotDeviceMessageTypeEnum.class)
  21 + private String type;
  22 +
  23 + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "report")
  24 + @NotEmpty(message = "标识符不能为空")
  25 + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举类
  26 +
  27 + @Schema(description = "请求参数", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private Object data; // 例如说:属性上报的 properties、事件上报的 params
  29 +
  30 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备日志分页查询 Request VO")
  9 +@Data
  10 +public class IotDeviceLogPageReqVO extends PageParam {
  11 +
  12 + @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
  13 + @NotEmpty(message = "设备标识不能为空")
  14 + private String deviceKey;
  15 +
  16 + @Schema(description = "消息类型", example = "property")
  17 + private String type; // 参见 IotDeviceMessageTypeEnum 枚举,精准匹配
  18 +
  19 + @Schema(description = "标识符", example = "temperature")
  20 + private String identifier; // 参见 IotDeviceMessageIdentifierEnum 枚举,模糊匹配
  21 +
  22 +}
0 \ No newline at end of file 23 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDeviceLogRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备日志 Response VO")
  9 +@Data
  10 +public class IotDeviceLogRespVO {
  11 +
  12 + @Schema(description = "日志编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private String id;
  14 +
  15 + @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "product123")
  16 + private String productKey;
  17 +
  18 + @Schema(description = "设备标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device123")
  19 + private String deviceKey;
  20 +
  21 + @Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "property")
  22 + private String type;
  23 +
  24 + @Schema(description = "标识符", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
  25 + private String identifier;
  26 +
  27 + @Schema(description = "日志内容", requiredMode = Schema.RequiredMode.REQUIRED)
  28 + private String content;
  29 +
  30 + @Schema(description = "上报时间", requiredMode = Schema.RequiredMode.REQUIRED)
  31 + private LocalDateTime reportTime;
  32 +
  33 + @Schema(description = "记录时间戳", requiredMode = Schema.RequiredMode.REQUIRED)
  34 + private LocalDateTime ts;
  35 +
  36 +}
0 \ No newline at end of file 37 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyHistoryPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import jakarta.validation.constraints.Size;
  8 +import lombok.Data;
  9 +import org.springframework.format.annotation.DateTimeFormat;
  10 +
  11 +import java.time.LocalDateTime;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  14 +
  15 +@Schema(description = "管理后台 - IoT 设备属性历史分页 Request VO")
  16 +@Data
  17 +public class IotDevicePropertyHistoryPageReqVO extends PageParam {
  18 +
  19 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "177")
  20 + @NotNull(message = "设备编号不能为空")
  21 + private Long deviceId;
  22 +
  23 + @Schema(description = "设备 Key", hidden = true)
  24 + private String deviceKey; // 非前端传递,后端自己查询设置
  25 +
  26 + @Schema(description = "属性标识符", requiredMode = Schema.RequiredMode.REQUIRED)
  27 + @NotEmpty(message = "属性标识符不能为空")
  28 + private String identifier;
  29 +
  30 + @Schema(description = "时间范围", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
  31 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  32 + @Size(min = 2, max = 2, message = "请选择时间范围")
  33 + private LocalDateTime[] times;
  34 +
  35 +}
0 \ No newline at end of file 36 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/data/IotDevicePropertyRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.data;
  2 +
  3 +import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Schema(description = "管理后台 - IoT 设备属性 Response VO")
  8 +@Data
  9 +public class IotDevicePropertyRespVO {
  10 +
  11 + @Schema(description = "属性定义", requiredMode = Schema.RequiredMode.REQUIRED)
  12 + private ThingModelProperty property;
  13 +
  14 + @Schema(description = "最新值", requiredMode = Schema.RequiredMode.REQUIRED)
  15 + private Object value;
  16 +
  17 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  18 + private Long updateTime; // 由于从 TDengine 查询出来的是 Long 类型,所以这里也使用 Long 类型
  19 +
  20 +}
0 \ No newline at end of file 21 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportExcelVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotEmpty;
  6 +import lombok.AllArgsConstructor;
  7 +import lombok.Builder;
  8 +import lombok.Data;
  9 +import lombok.NoArgsConstructor;
  10 +import lombok.experimental.Accessors;
  11 +
  12 +/**
  13 + * 设备 Excel 导入 VO
  14 + */
  15 +@Data
  16 +@Builder
  17 +@AllArgsConstructor
  18 +@NoArgsConstructor
  19 +@Accessors(chain = false) // 设置 chain = false,避免设备导入有问题
  20 +public class IotDeviceImportExcelVO {
  21 +
  22 + @ExcelProperty("设备名称")
  23 + @NotEmpty(message = "设备名称不能为空")
  24 + private String deviceName;
  25 +
  26 + @ExcelProperty("父设备名称")
  27 + @Schema(description = "父设备名称", example = "网关001")
  28 + private String parentDeviceName;
  29 +
  30 + @ExcelProperty("产品标识")
  31 + @NotEmpty(message = "产品标识不能为空")
  32 + private String productKey;
  33 +
  34 + @ExcelProperty("设备分组")
  35 + private String groupNames;
  36 +
  37 +}
0 \ No newline at end of file 38 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceImportRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备导入 Response VO")
  11 +@Data
  12 +@Builder
  13 +public class IotDeviceImportRespVO {
  14 +
  15 + @Schema(description = "创建成功的设备名称数组", requiredMode = Schema.RequiredMode.REQUIRED)
  16 + private List<String> createDeviceNames;
  17 +
  18 + @Schema(description = "更新成功的设备名称数组", requiredMode = Schema.RequiredMode.REQUIRED)
  19 + private List<String> updateDeviceNames;
  20 +
  21 + @Schema(description = "导入失败的设备集合,key为设备名称,value为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private Map<String, String> failureDeviceNames;
  23 +}
0 \ No newline at end of file 24 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceMqttConnectionParamsRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
  4 +import com.alibaba.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备 MQTT 连接参数 Response VO")
  9 +@Data
  10 +@ExcelIgnoreUnannotated
  11 +public class IotDeviceMqttConnectionParamsRespVO {
  12 +
  13 + @Schema(description = "MQTT 客户端 ID", example = "24602")
  14 + @ExcelProperty("MQTT 客户端 ID")
  15 + private String mqttClientId;
  16 +
  17 + @Schema(description = "MQTT 用户名", example = "芋艿")
  18 + @ExcelProperty("MQTT 用户名")
  19 + private String mqttUsername;
  20 +
  21 + @Schema(description = "MQTT 密码")
  22 + @ExcelProperty("MQTT 密码")
  23 + private String mqttPassword;
  24 +
  25 +}
0 \ No newline at end of file 26 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDevicePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  5 +import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStateEnum;
  6 +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - IoT 设备分页 Request VO")
  11 +@Data
  12 +public class IotDevicePageReqVO extends PageParam {
  13 +
  14 + @Schema(description = "设备名称", example = "王五")
  15 + private String deviceName;
  16 +
  17 + @Schema(description = "备注名称", example = "张三")
  18 + private String nickname;
  19 +
  20 + @Schema(description = "产品编号", example = "26202")
  21 + private Long productId;
  22 +
  23 + @Schema(description = "设备类型", example = "1")
  24 + @InEnum(IotProductDeviceTypeEnum.class)
  25 + private Integer deviceType;
  26 +
  27 + @Schema(description = "设备状态", example = "1")
  28 + @InEnum(IotDeviceStateEnum.class)
  29 + private Integer status;
  30 +
  31 + @Schema(description = "设备分组编号", example = "1024")
  32 + private Long groupId;
  33 +
  34 +}
0 \ No newline at end of file 35 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
1 -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; 1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
2 2
  3 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  4 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
3 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; 5 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
4 import com.alibaba.excel.annotation.ExcelProperty; 6 import com.alibaba.excel.annotation.ExcelProperty;
5 import io.swagger.v3.oas.annotations.media.Schema; 7 import io.swagger.v3.oas.annotations.media.Schema;
6 import lombok.Data; 8 import lombok.Data;
7 9
8 -import java.math.BigDecimal;  
9 import java.time.LocalDateTime; 10 import java.time.LocalDateTime;
  11 +import java.util.Set;
  12 +
  13 +import static cn.iocoder.yudao.module.iot.enums.DictTypeConstants.DEVICE_STATE;
10 14
11 @Schema(description = "管理后台 - IoT 设备 Response VO") 15 @Schema(description = "管理后台 - IoT 设备 Response VO")
12 @Data 16 @Data
@@ -21,9 +25,24 @@ public class IotDeviceRespVO { @@ -21,9 +25,24 @@ public class IotDeviceRespVO {
21 private String deviceKey; 25 private String deviceKey;
22 26
23 @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") 27 @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
24 - @ExcelProperty("设备名称备") 28 + @ExcelProperty("设备名称")
25 private String deviceName; 29 private String deviceName;
26 30
  31 + @Schema(description = "设备备注名称", example = "张三")
  32 + @ExcelProperty("设备备注名称")
  33 + private String nickname;
  34 +
  35 + @Schema(description = "设备序列号", example = "1024")
  36 + @ExcelProperty("设备序列号")
  37 + private String serialNumber;
  38 +
  39 + @Schema(description = "设备图片", example = "我是一名码农")
  40 + @ExcelProperty("设备图片")
  41 + private String picUrl;
  42 +
  43 + @Schema(description = "设备分组编号数组", example = "1,2")
  44 + private Set<Long> groupIds;
  45 +
27 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") 46 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
28 @ExcelProperty("产品编号") 47 @ExcelProperty("产品编号")
29 private Long productId; 48 private Long productId;
@@ -36,28 +55,21 @@ public class IotDeviceRespVO { @@ -36,28 +55,21 @@ public class IotDeviceRespVO {
36 @ExcelProperty("设备类型") 55 @ExcelProperty("设备类型")
37 private Integer deviceType; 56 private Integer deviceType;
38 57
39 - @Schema(description = "设备备注名称", example = "张三")  
40 - @ExcelProperty("设备备注名称")  
41 - private String nickname;  
42 -  
43 @Schema(description = "网关设备 ID", example = "16380") 58 @Schema(description = "网关设备 ID", example = "16380")
44 private Long gatewayId; 59 private Long gatewayId;
45 60
46 @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 61 @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
47 - @ExcelProperty("设备状态")  
48 - private Integer status;  
49 -  
50 - @Schema(description = "设备状态最后更新时间")  
51 - @ExcelProperty("设备状态最后更新时间")  
52 - private LocalDateTime statusLastUpdateTime; 62 + @ExcelProperty(value = "设备状态", converter = DictConvert.class)
  63 + @DictFormat(DEVICE_STATE)
  64 + private Integer state;
53 65
54 @Schema(description = "最后上线时间") 66 @Schema(description = "最后上线时间")
55 @ExcelProperty("最后上线时间") 67 @ExcelProperty("最后上线时间")
56 - private LocalDateTime lastOnlineTime; 68 + private LocalDateTime onlineTime;
57 69
58 @Schema(description = "最后离线时间") 70 @Schema(description = "最后离线时间")
59 @ExcelProperty("最后离线时间") 71 @ExcelProperty("最后离线时间")
60 - private LocalDateTime lastOfflineTime; 72 + private LocalDateTime offlineTime;
61 73
62 @Schema(description = "设备激活时间") 74 @Schema(description = "设备激活时间")
63 @ExcelProperty("设备激活时间") 75 @ExcelProperty("设备激活时间")
@@ -67,22 +79,13 @@ public class IotDeviceRespVO { @@ -67,22 +79,13 @@ public class IotDeviceRespVO {
67 @ExcelProperty("设备密钥") 79 @ExcelProperty("设备密钥")
68 private String deviceSecret; 80 private String deviceSecret;
69 81
70 - @Schema(description = "MQTT 客户端 ID", example = "24602")  
71 - @ExcelProperty("MQTT 客户端 ID")  
72 - private String mqttClientId;  
73 -  
74 - @Schema(description = "MQTT 用户名", example = "芋艿")  
75 - @ExcelProperty("MQTT 用户名")  
76 - private String mqttUsername;  
77 -  
78 - @Schema(description = "MQTT 密码")  
79 - @ExcelProperty("MQTT 密码")  
80 - private String mqttPassword;  
81 -  
82 @Schema(description = "认证类型(如一机一密、动态注册)", example = "2") 82 @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
83 @ExcelProperty("认证类型(如一机一密、动态注册)") 83 @ExcelProperty("认证类型(如一机一密、动态注册)")
84 private String authType; 84 private String authType;
85 85
  86 + @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
  87 + private String config;
  88 +
86 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) 89 @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
87 @ExcelProperty("创建时间") 90 @ExcelProperty("创建时间")
88 private LocalDateTime createTime; 91 private LocalDateTime createTime;
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceSaveReqVO.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
1 -package cn.iocoder.yudao.module.iot.controller.admin.device.vo; 1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.Size;
4 import lombok.Data; 5 import lombok.Data;
5 6
  7 +import java.util.Set;
  8 +
6 @Schema(description = "管理后台 - IoT 设备新增/修改 Request VO") 9 @Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
7 @Data 10 @Data
8 public class IotDeviceSaveReqVO { 11 public class IotDeviceSaveReqVO {
@@ -10,13 +13,32 @@ public class IotDeviceSaveReqVO { @@ -10,13 +13,32 @@ public class IotDeviceSaveReqVO {
10 @Schema(description = "设备编号", example = "177") 13 @Schema(description = "设备编号", example = "177")
11 private Long id; 14 private Long id;
12 15
13 - @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五") 16 + @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.AUTO, example = "177")
  17 + @Size(max = 50, message = "设备编号长度不能超过 50 个字符")
  18 + private String deviceKey;
  19 +
  20 + @Schema(description = "设备名称", requiredMode = Schema.RequiredMode.AUTO, example = "王五")
14 private String deviceName; 21 private String deviceName;
15 22
16 @Schema(description = "备注名称", example = "张三") 23 @Schema(description = "备注名称", example = "张三")
17 private String nickname; 24 private String nickname;
18 25
  26 + @Schema(description = "设备序列号", example = "123456")
  27 + private String serialNumber;
  28 +
  29 + @Schema(description = "设备图片", example = "https://iocoder.cn/1.png")
  30 + private String picUrl;
  31 +
  32 + @Schema(description = "设备分组编号数组", example = "1,2")
  33 + private Set<Long> groupIds;
  34 +
19 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202") 35 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
20 private Long productId; 36 private Long productId;
21 37
  38 + @Schema(description = "网关设备 ID", example = "16380")
  39 + private Long gatewayId;
  40 +
  41 + @Schema(description = "设备配置", example = "{\"abc\": \"efg\"}")
  42 + private String config;
  43 +
22 } 44 }
23 \ No newline at end of file 45 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceUpdateGroupReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import lombok.Data;
  6 +
  7 +import java.util.Set;
  8 +
  9 +@Schema(description = "管理后台 - IoT 设备更新分组 Request VO")
  10 +@Data
  11 +public class IotDeviceUpdateGroupReqVO {
  12 +
  13 + @Schema(description = "设备编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
  14 + @NotEmpty(message = "设备编号列表不能为空")
  15 + private Set<Long> ids;
  16 +
  17 + @Schema(description = "分组编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2,3")
  18 + @NotEmpty(message = "分组编号列表不能为空")
  19 + private Set<Long> groupIds;
  20 +
  21 +}
0 \ No newline at end of file 22 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - IoT 设备分组分页 Request VO")
  15 +@Data
  16 +public class IotDeviceGroupPageReqVO extends PageParam {
  17 +
  18 + @Schema(description = "分组名字", example = "李四")
  19 + private String name;
  20 +
  21 + @Schema(description = "创建时间")
  22 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  23 + private LocalDateTime[] createTime;
  24 +
  25 +}
0 \ No newline at end of file 26 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备分组 Response VO")
  9 +@Data
  10 +public class IotDeviceGroupRespVO {
  11 +
  12 + @Schema(description = "分组 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3583")
  13 + private Long id;
  14 +
  15 + @Schema(description = "分组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  16 + private String name;
  17 +
  18 + @Schema(description = "分组状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer status;
  20 +
  21 + @Schema(description = "分组描述", example = "你说的对")
  22 + private String description;
  23 +
  24 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  25 + private LocalDateTime createTime;
  26 +
  27 + @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  28 + private Long deviceCount;
  29 +
  30 +}
0 \ No newline at end of file 31 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.device.vo.group;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +@Schema(description = "管理后台 - IoT 设备分组新增/修改 Request VO")
  9 +@Data
  10 +public class IotDeviceGroupSaveReqVO {
  11 +
  12 + @Schema(description = "分组 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "3583")
  13 + private Long id;
  14 +
  15 + @Schema(description = "分组名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
  16 + @NotEmpty(message = "分组名字不能为空")
  17 + private String name;
  18 +
  19 + @Schema(description = "分组状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  20 + @NotNull(message = "分组状态不能为空")
  21 + private Integer status;
  22 +
  23 + @Schema(description = "分组描述", example = "你说的对")
  24 + private String description;
  25 +
  26 +}
0 \ No newline at end of file 27 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaFirmwareController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
  9 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO;
  10 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
  11 +import cn.iocoder.yudao.module.iot.service.ota.IotOtaFirmwareService;
  12 +import io.swagger.v3.oas.annotations.Operation;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.*;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - IoT OTA 固件")
  23 +@RestController
  24 +@RequestMapping("/iot/ota-firmware")
  25 +@Validated
  26 +public class IotOtaFirmwareController {
  27 +
  28 + @Resource
  29 + private IotOtaFirmwareService otaFirmwareService;
  30 +
  31 + @PostMapping("/create")
  32 + @Operation(summary = "创建 OTA 固件")
  33 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:create')")
  34 + public CommonResult<Long> createOtaFirmware(@Valid @RequestBody IotOtaFirmwareCreateReqVO createReqVO) {
  35 + return success(otaFirmwareService.createOtaFirmware(createReqVO));
  36 + }
  37 +
  38 + @PutMapping("/update")
  39 + @Operation(summary = "更新 OTA 固件")
  40 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:update')")
  41 + public CommonResult<Boolean> updateOtaFirmware(@Valid @RequestBody IotOtaFirmwareUpdateReqVO updateReqVO) {
  42 + otaFirmwareService.updateOtaFirmware(updateReqVO);
  43 + return success(true);
  44 + }
  45 +
  46 + @GetMapping("/get")
  47 + @Operation(summary = "获得 OTA 固件")
  48 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
  49 + public CommonResult<IotOtaFirmwareRespVO> getOtaFirmware(@RequestParam("id") Long id) {
  50 + IotOtaFirmwareDO otaFirmware = otaFirmwareService.getOtaFirmware(id);
  51 + return success(BeanUtils.toBean(otaFirmware, IotOtaFirmwareRespVO.class));
  52 + }
  53 +
  54 + @GetMapping("/page")
  55 + @Operation(summary = "获得 OTA 固件分页")
  56 + @PreAuthorize("@ss.hasPermission('iot:ota-firmware:query')")
  57 + public CommonResult<PageResult<IotOtaFirmwareRespVO>> getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO) {
  58 + PageResult<IotOtaFirmwareDO> pageResult = otaFirmwareService.getOtaFirmwarePage(pageReqVO);
  59 + return success(BeanUtils.toBean(pageResult, IotOtaFirmwareRespVO.class));
  60 + }
  61 +
  62 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeRecordController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.record.IotOtaUpgradeRecordRespVO;
  8 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeRecordDO;
  9 +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeRecordService;
  10 +import io.swagger.v3.oas.annotations.Operation;
  11 +import io.swagger.v3.oas.annotations.Parameter;
  12 +import io.swagger.v3.oas.annotations.tags.Tag;
  13 +import jakarta.annotation.Resource;
  14 +import jakarta.validation.Valid;
  15 +import org.springframework.security.access.prepost.PreAuthorize;
  16 +import org.springframework.validation.annotation.Validated;
  17 +import org.springframework.web.bind.annotation.*;
  18 +
  19 +import java.util.Map;
  20 +
  21 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  22 +
  23 +@Tag(name = "管理后台 - IoT OTA 升级记录")
  24 +@RestController
  25 +@RequestMapping("/iot/ota-upgrade-record")
  26 +@Validated
  27 +public class IotOtaUpgradeRecordController {
  28 +
  29 + @Resource
  30 + private IotOtaUpgradeRecordService upgradeRecordService;
  31 +
  32 + @GetMapping("/get-statistics")
  33 + @Operation(summary = "固件升级设备统计")
  34 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  35 + @Parameter(name = "firmwareId", description = "固件编号", required = true, example = "1024")
  36 + public CommonResult<Map<Integer, Long>> getOtaUpgradeRecordStatistics(@RequestParam(value = "firmwareId") Long firmwareId) {
  37 + return success(upgradeRecordService.getOtaUpgradeRecordStatistics(firmwareId));
  38 + }
  39 +
  40 + @GetMapping("/get-count")
  41 + @Operation(summary = "获得升级记录分页 tab 数量")
  42 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  43 + public CommonResult<Map<Integer, Long>> getOtaUpgradeRecordCount(
  44 + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) {
  45 + return success(upgradeRecordService.getOtaUpgradeRecordCount(pageReqVO));
  46 + }
  47 +
  48 + @GetMapping("/page")
  49 + @Operation(summary = "获得升级记录分页")
  50 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  51 + public CommonResult<PageResult<IotOtaUpgradeRecordRespVO>> getUpgradeRecordPage(
  52 + @Valid IotOtaUpgradeRecordPageReqVO pageReqVO) {
  53 + PageResult<IotOtaUpgradeRecordDO> pageResult = upgradeRecordService.getUpgradeRecordPage(pageReqVO);
  54 + return success(BeanUtils.toBean(pageResult, IotOtaUpgradeRecordRespVO.class));
  55 + }
  56 +
  57 + @GetMapping("/get")
  58 + @Operation(summary = "获得升级记录")
  59 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:query')")
  60 + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
  61 + public CommonResult<IotOtaUpgradeRecordRespVO> getUpgradeRecord(@RequestParam("id") Long id) {
  62 + IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordService.getUpgradeRecord(id);
  63 + return success(BeanUtils.toBean(upgradeRecord, IotOtaUpgradeRecordRespVO.class));
  64 + }
  65 +
  66 + @PutMapping("/retry")
  67 + @Operation(summary = "重试升级记录")
  68 + @PreAuthorize("@ss.hasPermission('iot:ota-upgrade-record:retry')")
  69 + @Parameter(name = "id", description = "升级记录编号", required = true, example = "1024")
  70 + public CommonResult<Boolean> retryUpgradeRecord(@RequestParam("id") Long id) {
  71 + upgradeRecordService.retryUpgradeRecord(id);
  72 + return success(true);
  73 + }
  74 +
  75 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/IotOtaUpgradeTaskController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskPageReqVO;
  7 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskRespVO;
  8 +import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.upgrade.task.IotOtaUpgradeTaskSaveReqVO;
  9 +import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaUpgradeTaskDO;
  10 +import cn.iocoder.yudao.module.iot.service.ota.IotOtaUpgradeTaskService;
  11 +import io.swagger.v3.oas.annotations.Operation;
  12 +import io.swagger.v3.oas.annotations.Parameter;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.*;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - IoT OTA 升级任务")
  23 +@RestController
  24 +@RequestMapping("/iot/ota-upgrade-task")
  25 +@Validated
  26 +public class IotOtaUpgradeTaskController {
  27 +
  28 + @Resource
  29 + private IotOtaUpgradeTaskService upgradeTaskService;
  30 +
  31 + @PostMapping("/create")
  32 + @Operation(summary = "创建升级任务")
  33 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:create')")
  34 + public CommonResult<Long> createUpgradeTask(@Valid @RequestBody IotOtaUpgradeTaskSaveReqVO createReqVO) {
  35 + return success(upgradeTaskService.createUpgradeTask(createReqVO));
  36 + }
  37 +
  38 + @PostMapping("/cancel")
  39 + @Operation(summary = "取消升级任务")
  40 + @Parameter(name = "id", description = "升级任务编号", required = true)
  41 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:cancel')")
  42 + public CommonResult<Boolean> cancelUpgradeTask(@RequestParam("id") Long id) {
  43 + upgradeTaskService.cancelUpgradeTask(id);
  44 + return success(true);
  45 + }
  46 +
  47 + @GetMapping("/page")
  48 + @Operation(summary = "获得升级任务分页")
  49 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')")
  50 + public CommonResult<PageResult<IotOtaUpgradeTaskRespVO>> getUpgradeTaskPage(@Valid IotOtaUpgradeTaskPageReqVO pageReqVO) {
  51 + PageResult<IotOtaUpgradeTaskDO> pageResult = upgradeTaskService.getUpgradeTaskPage(pageReqVO);
  52 + return success(BeanUtils.toBean(pageResult, IotOtaUpgradeTaskRespVO.class));
  53 + }
  54 +
  55 + @GetMapping("/get")
  56 + @Operation(summary = "获得升级任务")
  57 + @Parameter(name = "id", description = "升级任务编号", required = true, example = "1024")
  58 + @PreAuthorize(value = "@ss.hasPermission('iot:ota-upgrade-task:query')")
  59 + public CommonResult<IotOtaUpgradeTaskRespVO> getUpgradeTask(@RequestParam("id") Long id) {
  60 + IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(id);
  61 + return success(BeanUtils.toBean(upgradeTask, IotOtaUpgradeTaskRespVO.class));
  62 + }
  63 +
  64 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotEmpty;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +
  8 +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
  9 +
  10 +@Schema(description = "管理后台 - IoT OTA 固件创建 Request VO")
  11 +@Data
  12 +public class IotOtaFirmwareCreateReqVO {
  13 +
  14 + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "智能开关固件")
  15 + @NotEmpty(message = "固件名称不能为空")
  16 + private String name;
  17 +
  18 + @Schema(description = "固件描述", example = "某品牌型号固件,测试用")
  19 + private String description;
  20 +
  21 + @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0")
  22 + @NotEmpty(message = "版本号不能为空")
  23 + private String version;
  24 +
  25 + @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024")
  26 + @NotNull(message = "产品编号不能为空")
  27 + private String productId;
  28 +
  29 + @Schema(description = "签名方式", example = "MD5")
  30 + // TODO @li:是不是必传哈
  31 + private String signMethod;
  32 +
  33 + @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip")
  34 + @NotEmpty(message = "固件文件 URL 不能为空")
  35 + private String fileUrl;
  36 +
  37 + @Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}")
  38 + private String information;
  39 +
  40 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +
  7 +@Data
  8 +@Schema(description = "管理后台 - IoT OTA 固件分页 Request VO")
  9 +public class IotOtaFirmwarePageReqVO extends PageParam {
  10 +
  11 + /**
  12 + * 固件名称
  13 + */
  14 + @Schema(description = "固件名称", example = "智能开关固件")
  15 + private String name;
  16 +
  17 + /**
  18 + * 产品标识
  19 + */
  20 + @Schema(description = "产品标识", example = "1024")
  21 + private String productId;
  22 +
  23 +}
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
  2 +
  3 +import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
  4 +import com.fhs.core.trans.anno.Trans;
  5 +import com.fhs.core.trans.constant.TransType;
  6 +import com.fhs.core.trans.vo.VO;
  7 +import io.swagger.v3.oas.annotations.media.Schema;
  8 +import lombok.Data;
  9 +
  10 +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
  11 +
  12 +@Data
  13 +@Schema(description = "管理后台 - IoT OTA 固件 Response VO")
  14 +public class IotOtaFirmwareRespVO implements VO {
  15 +
  16 + /**
  17 + * 固件编号
  18 + */
  19 + @Schema(description = "固件编号", requiredMode = REQUIRED, example = "1024")
  20 + private Long id;
  21 + /**
  22 + * 固件名称
  23 + */
  24 + @Schema(description = "固件名称", requiredMode = REQUIRED, example = "OTA固件")
  25 + private String name;
  26 + /**
  27 + * 固件描述
  28 + */
  29 + @Schema(description = "固件描述")
  30 + private String description;
  31 + /**
  32 + * 版本号
  33 + */
  34 + @Schema(description = "版本号", requiredMode = REQUIRED, example = "1.0.0")
  35 + private String version;
  36 +
  37 + /**
  38 + * 产品编号
  39 + * <p>
  40 + * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
  41 + */
  42 + @Schema(description = "产品编号", requiredMode = REQUIRED, example = "1024")
  43 + @Trans(type = TransType.SIMPLE, target = IotProductDO.class, fields = {"name"}, refs = {"productName"})
  44 + private String productId;
  45 + /**
  46 + * 产品标识
  47 + * <p>
  48 + * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()}
  49 + */
  50 + @Schema(description = "产品标识", requiredMode = REQUIRED, example = "iot-product-key")
  51 + private String productKey;
  52 + /**
  53 + * 产品名称
  54 + */
  55 + @Schema(description = "产品名称", requiredMode = REQUIRED, example = "OTA产品")
  56 + private String productName;
  57 + /**
  58 + * 签名方式
  59 + * <p>
  60 + * 例如说:MD5、SHA256
  61 + */
  62 + @Schema(description = "签名方式", example = "MD5")
  63 + private String signMethod;
  64 + /**
  65 + * 固件文件签名
  66 + */
  67 + @Schema(description = "固件文件签名", example = "1024")
  68 + private String fileSign;
  69 + /**
  70 + * 固件文件大小
  71 + */
  72 + @Schema(description = "固件文件大小", requiredMode = REQUIRED, example = "1024")
  73 + private Long fileSize;
  74 + /**
  75 + * 固件文件 URL
  76 + */
  77 + @Schema(description = "固件文件 URL", requiredMode = REQUIRED, example = "https://www.iocoder.cn")
  78 + private String fileUrl;
  79 + /**
  80 + * 自定义信息,建议使用 JSON 格式
  81 + */
  82 + @Schema(description = "自定义信息,建议使用 JSON 格式")
  83 + private String information;
  84 +
  85 +}