mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-18 19:20:05 +08:00
修改:IOT 根据属性列表,自动生成属性上报事件和属性设置、获取服务
This commit is contained in:
parent
9e77692414
commit
1f8576f643
@ -5,45 +5,139 @@ tenant-id: {{adminTenentId}}
|
||||
Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"productId": 1,
|
||||
"productKey": "123456",
|
||||
"productId": 1002,
|
||||
"productKey": "smart-sensor-002",
|
||||
"properties": [
|
||||
{
|
||||
"identifier": "Temperature",
|
||||
"name": "温度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": -40.0,
|
||||
"max": 125.0,
|
||||
"step": 0.1,
|
||||
"unit": "℃"
|
||||
}
|
||||
},
|
||||
"description": "当前温度值"
|
||||
},
|
||||
{
|
||||
"identifier": "Humidity",
|
||||
"name": "湿度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": 0.0,
|
||||
"max": 100.0,
|
||||
"step": 0.1,
|
||||
"unit": "%"
|
||||
}
|
||||
},
|
||||
"description": "当前湿度值"
|
||||
},
|
||||
{
|
||||
"identifier": "GeoLocation",
|
||||
"name": "地理位置",
|
||||
"accessMode": "r",
|
||||
"required": false,
|
||||
"dataType": {
|
||||
"type": "struct",
|
||||
"specs": [
|
||||
{
|
||||
"identifier": "Longitude",
|
||||
"name": "经度",
|
||||
"dataType": {
|
||||
"type": "double",
|
||||
"specs": {
|
||||
"min": -180.0,
|
||||
"max": 180.0,
|
||||
"step": 0.000001,
|
||||
"unit": "°"
|
||||
}
|
||||
},
|
||||
"description": "设备所在位置的经度"
|
||||
},
|
||||
{
|
||||
"identifier": "Latitude",
|
||||
"name": "纬度",
|
||||
"dataType": {
|
||||
"type": "double",
|
||||
"specs": {
|
||||
"min": -90.0,
|
||||
"max": 90.0,
|
||||
"step": 0.000001,
|
||||
"unit": "°"
|
||||
}
|
||||
},
|
||||
"description": "设备所在位置的纬度"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "设备的地理位置信息"
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"identifier": "Reboot",
|
||||
"name": "重启设备",
|
||||
"callType": "async",
|
||||
"inputData": [],
|
||||
"description": "远程重启设备",
|
||||
"method": "thing.service.reboot"
|
||||
},
|
||||
{
|
||||
"identifier": "SetThreshold",
|
||||
"name": "设置温度阈值",
|
||||
"callType": "sync",
|
||||
"inputData": [
|
||||
{
|
||||
"identifier": "Threshold",
|
||||
"name": "阈值",
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": -40.0,
|
||||
"max": 125.0,
|
||||
"step": 0.1,
|
||||
"unit": "℃"
|
||||
}
|
||||
},
|
||||
"description": "报警温度阈值"
|
||||
}
|
||||
],
|
||||
"description": "设置设备的温度报警阈值",
|
||||
"method": "thing.service.setThreshold"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"identifier": "HighTemperatureAlert",
|
||||
"name": "高温报警",
|
||||
"type": "alert",
|
||||
"outputData": [
|
||||
{
|
||||
"identifier": "CurrentTemperature",
|
||||
"name": "当前温度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": "-40",
|
||||
"max": "120",
|
||||
"unit": "°C",
|
||||
"unitName": "摄氏度",
|
||||
"step": "0.1"
|
||||
}
|
||||
"unit": "℃"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identifier": "CurrentHumidity",
|
||||
"name": "当前湿度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": "0",
|
||||
"max": "100",
|
||||
"unit": "%",
|
||||
"unitName": "百分比",
|
||||
"step": "0.1"
|
||||
}
|
||||
}
|
||||
"description": "触发报警时的温度值"
|
||||
}
|
||||
],
|
||||
"services": "{}",
|
||||
"events": "{}"
|
||||
"description": "当温度超过阈值时触发高温报警事件",
|
||||
"method": "thing.event.highTemperatureAlert"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
### 请求 /iot/think-model-function/update 接口 => 成功
|
||||
PUT {{baseUrl}}/iot/think-model-function/update
|
||||
@ -53,45 +147,136 @@ Authorization: Bearer {{token}}
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"productId": 1,
|
||||
"productKey": "123456",
|
||||
"productId": 1001,
|
||||
"productKey": "smart-sensor-001",
|
||||
"properties": [
|
||||
{
|
||||
"identifier": "Temperature",
|
||||
"name": "温度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": -40.0,
|
||||
"max": 125.0,
|
||||
"step": 0.1,
|
||||
"unit": "℃"
|
||||
}
|
||||
},
|
||||
"description": "当前温度值"
|
||||
},
|
||||
{
|
||||
"identifier": "Humidity",
|
||||
"name": "湿度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": 0.0,
|
||||
"max": 100.0,
|
||||
"step": 0.1,
|
||||
"unit": "%"
|
||||
}
|
||||
},
|
||||
"description": "当前湿度值"
|
||||
},
|
||||
{
|
||||
"identifier": "GeoLocation",
|
||||
"name": "地理位置",
|
||||
"accessMode": "r",
|
||||
"required": false,
|
||||
"dataType": {
|
||||
"type": "struct",
|
||||
"specs": [
|
||||
{
|
||||
"identifier": "Longitude",
|
||||
"name": "经度",
|
||||
"dataType": {
|
||||
"type": "double",
|
||||
"specs": {
|
||||
"min": -180.0,
|
||||
"max": 180.0,
|
||||
"step": 0.000001,
|
||||
"unit": "°"
|
||||
}
|
||||
},
|
||||
"description": "设备所在位置的经度"
|
||||
},
|
||||
{
|
||||
"identifier": "Latitude",
|
||||
"name": "纬度",
|
||||
"dataType": {
|
||||
"type": "double",
|
||||
"specs": {
|
||||
"min": -90.0,
|
||||
"max": 90.0,
|
||||
"step": 0.000001,
|
||||
"unit": "°"
|
||||
}
|
||||
},
|
||||
"description": "设备所在位置的纬度"
|
||||
}
|
||||
]
|
||||
},
|
||||
"description": "设备的地理位置信息"
|
||||
}
|
||||
],
|
||||
"services": [
|
||||
{
|
||||
"identifier": "Reboot",
|
||||
"name": "重启设备",
|
||||
"callType": "async",
|
||||
"inputData": [],
|
||||
"description": "远程重启设备"
|
||||
},
|
||||
{
|
||||
"identifier": "SetThreshold",
|
||||
"name": "设置温度阈值",
|
||||
"callType": "sync",
|
||||
"inputData": [
|
||||
{
|
||||
"identifier": "Threshold",
|
||||
"name": "阈值",
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": -40.0,
|
||||
"max": 125.0,
|
||||
"step": 0.1,
|
||||
"unit": "℃"
|
||||
}
|
||||
},
|
||||
"description": "报警温度阈值"
|
||||
}
|
||||
],
|
||||
"description": "设置设备的温度报警阈值"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"identifier": "HighTemperatureAlert",
|
||||
"name": "高温报警",
|
||||
"type": "alert",
|
||||
"outputData": [
|
||||
{
|
||||
"identifier": "CurrentTemperature",
|
||||
"name": "当前温度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": "-40",
|
||||
"max": "130",
|
||||
"unit": "°C",
|
||||
"unitName": "摄氏度",
|
||||
"step": "0.1"
|
||||
}
|
||||
"unit": "℃"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identifier": "CurrentHumidity",
|
||||
"name": "当前湿度",
|
||||
"accessMode": "r",
|
||||
"required": true,
|
||||
"dataType": {
|
||||
"type": "float",
|
||||
"specs": {
|
||||
"min": "0",
|
||||
"max": "100",
|
||||
"unit": "%",
|
||||
"unitName": "百分比",
|
||||
"step": "0.1"
|
||||
}
|
||||
}
|
||||
"description": "触发报警时的温度值"
|
||||
}
|
||||
],
|
||||
"services": "{}",
|
||||
"events": "{}"
|
||||
"description": "当温度超过阈值时触发高温报警事件"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功
|
||||
GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456
|
||||
|
@ -0,0 +1,12 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThingModelArgument {
|
||||
private String identifier;
|
||||
private String name;
|
||||
private ThingModelDataType dataType;
|
||||
private String direction; // 用于区分输入或输出参数,"input" 或 "output"
|
||||
private String description;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThingModelArraySpecs {
|
||||
private int size; // 数组长度
|
||||
private ThingModelDataType item; // 数组元素的类型
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelArrayType extends ThingModelDataType {
|
||||
private ThingModelArraySpecs specs;
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelBoolType extends ThingModelDataType {
|
||||
// Bool 类型一般不需要额外的 specs
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"),
|
||||
@JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"),
|
||||
@JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"),
|
||||
@JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"),
|
||||
@JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"),
|
||||
@JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"),
|
||||
@JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"),
|
||||
@JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"),
|
||||
@JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array")
|
||||
})
|
||||
public abstract class ThingModelDataType {
|
||||
private String type;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelDateType extends ThingModelDataType {
|
||||
// Date 类型一般不需要额外的 specs
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelDoubleType extends ThingModelDataType {
|
||||
private ThingModelDoubleSpecs specs;
|
||||
}
|
||||
|
||||
@Data
|
||||
class ThingModelDoubleSpecs {
|
||||
private Double min;
|
||||
private Double max;
|
||||
private Double step;
|
||||
private String unit;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelEnumType extends ThingModelDataType {
|
||||
private Map<String, String> specs; // 枚举值和描述的键值对
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ThingModelEvent {
|
||||
private String identifier;
|
||||
private String name;
|
||||
private String type; // "info"、"alert"、"error"
|
||||
private List<ThingModelArgument> outputData;
|
||||
private String description;
|
||||
private String method;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelFloatType extends ThingModelDataType {
|
||||
private ThingModelFloatSpecs specs;
|
||||
}
|
||||
|
||||
@Data
|
||||
class ThingModelFloatSpecs {
|
||||
private Float min;
|
||||
private Float max;
|
||||
private Float step;
|
||||
private String unit;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelIntType extends ThingModelDataType {
|
||||
private ThingModelIntSpecs specs;
|
||||
}
|
||||
|
||||
@Data
|
||||
class ThingModelIntSpecs {
|
||||
private Integer min;
|
||||
private Integer max;
|
||||
private Integer step;
|
||||
private String unit;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThingModelProperty {
|
||||
private String identifier;
|
||||
private String name;
|
||||
private String accessMode; // "rw"、"r"、"w"
|
||||
private boolean required;
|
||||
private ThingModelDataType dataType;
|
||||
private String description;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ThingModelService {
|
||||
private String identifier;
|
||||
private String name;
|
||||
private String callType; // "sync"、"async"
|
||||
private List<ThingModelArgument> inputData;
|
||||
private List<ThingModelArgument> outputData;
|
||||
private String description;
|
||||
private String method;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ThingModelStructField {
|
||||
private String identifier;
|
||||
private String name;
|
||||
private ThingModelDataType dataType;
|
||||
private String description;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelStructType extends ThingModelDataType {
|
||||
private List<ThingModelStructField> specs;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ThingModelTextType extends ThingModelDataType {
|
||||
private ThingModelTextSpecs specs;
|
||||
}
|
||||
|
||||
@Data
|
||||
class ThingModelTextSpecs {
|
||||
private Integer length; // 最大长度
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 产品物模型属性")
|
||||
@Data
|
||||
public class IotThingModelProperty {
|
||||
|
||||
@Schema(description = "属性标识符")
|
||||
private String identifier;
|
||||
|
||||
@Schema(description = "属性名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "访问模式 (r/rw)")
|
||||
private String accessMode;
|
||||
|
||||
@Schema(description = "是否必需")
|
||||
private boolean required;
|
||||
|
||||
@Schema(description = "数据类型")
|
||||
private DataType dataType;
|
||||
|
||||
@Schema(description = "数据类型")
|
||||
@Data
|
||||
public static class DataType {
|
||||
|
||||
@Schema(description = "数据类型(float, double, struct, enum等)")
|
||||
private String type;
|
||||
|
||||
@Schema(description = "单一类型的规格(适用于float, double等)")
|
||||
private Specs specs;
|
||||
|
||||
@Schema(description = "结构体字段(适用于struct类型)")
|
||||
private List<StructField> structSpecs;
|
||||
|
||||
@Schema(description = "规格")
|
||||
@Data
|
||||
public static class Specs {
|
||||
|
||||
@Schema(description = "最小值")
|
||||
private String min;
|
||||
|
||||
@Schema(description = "最大值")
|
||||
private String max;
|
||||
|
||||
@Schema(description = "单位符号")
|
||||
private String unit;
|
||||
|
||||
@Schema(description = "单位名称")
|
||||
private String unitName;
|
||||
|
||||
@Schema(description = "步进值")
|
||||
private String step;
|
||||
}
|
||||
|
||||
@Schema(description = "结构体字段")
|
||||
@Data
|
||||
public static class StructField {
|
||||
|
||||
@Schema(description = "字段标识符")
|
||||
private String identifier;
|
||||
|
||||
@Schema(description = "字段名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "字段的数据类型")
|
||||
private DataType dataType;
|
||||
}
|
||||
}
|
||||
|
||||
@Schema(description = "枚举规格")
|
||||
@Data
|
||||
public static class EnumSpecs {
|
||||
|
||||
@Schema(description = "枚举值")
|
||||
private int value;
|
||||
|
||||
@Schema(description = "枚举名称")
|
||||
private String name;
|
||||
|
||||
public EnumSpecs(int value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO {
|
||||
|
||||
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("属性列表")
|
||||
private List<IotThingModelProperty> properties;
|
||||
private List<ThingModelProperty> properties;
|
||||
|
||||
@Schema(description = "服务列表")
|
||||
@ExcelProperty("服务列表")
|
||||
private String services;
|
||||
private List<ThingModelService> services;
|
||||
|
||||
@Schema(description = "事件列表")
|
||||
@ExcelProperty("事件列表")
|
||||
private String events;
|
||||
private List<ThingModelEvent> events;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@ExcelProperty("创建时间")
|
||||
|
@ -1,9 +1,14 @@
|
||||
package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
|
||||
@Data
|
||||
@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO {
|
||||
|
||||
@Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "属性列表不能为空")
|
||||
private List<IotThingModelProperty> properties;
|
||||
private List<ThingModelProperty> properties;
|
||||
|
||||
@Schema(description = "服务列表")
|
||||
private String services;
|
||||
private List<ThingModelService> services;
|
||||
|
||||
@Schema(description = "事件列表")
|
||||
private String events;
|
||||
private List<ThingModelEvent> events;
|
||||
|
||||
}
|
@ -1,16 +1,17 @@
|
||||
package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert {
|
||||
|
||||
IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class);
|
||||
|
||||
// 将 SaveReqVO 转换为 DO
|
||||
@Mapping(target = "properties", ignore = true)
|
||||
// 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段
|
||||
@Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))")
|
||||
@Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))")
|
||||
@Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))")
|
||||
IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean);
|
||||
|
||||
// 将 DO 转换为 RespVO
|
||||
@Mapping(target = "properties", ignore = true)
|
||||
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
|
||||
|
||||
// 处理 properties 字段的转换,从 VO 到 DO
|
||||
@AfterMapping
|
||||
default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) {
|
||||
target.setProperties(JSONUtil.toJsonStr(source.getProperties()));
|
||||
default String convertPropertiesToJson(List<ThingModelProperty> properties) {
|
||||
return properties != null ? JSONUtil.toJsonStr(properties) : "[]";
|
||||
}
|
||||
|
||||
// 处理 properties 字段的转换,从 DO 到 VO
|
||||
@AfterMapping
|
||||
default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) {
|
||||
target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class));
|
||||
default String convertServicesToJson(List<ThingModelService> services) {
|
||||
return services != null ? JSONUtil.toJsonStr(services) : "[]";
|
||||
}
|
||||
|
||||
default String convertEventsToJson(List<ThingModelEvent> events) {
|
||||
return events != null ? JSONUtil.toJsonStr(events) : "[]";
|
||||
}
|
||||
|
||||
// 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段
|
||||
@Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))")
|
||||
@Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))")
|
||||
@Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))")
|
||||
IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean);
|
||||
|
||||
default List<ThingModelProperty> convertJsonToProperties(String propertiesJson) {
|
||||
return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>();
|
||||
}
|
||||
|
||||
default List<ThingModelService> convertJsonToServices(String servicesJson) {
|
||||
return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>();
|
||||
}
|
||||
|
||||
default List<ThingModelEvent> convertJsonToEvents(String eventsJson) {
|
||||
return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>();
|
||||
}
|
||||
|
||||
// 批量转换 DO 列表到 RespVO 列表
|
||||
List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list);
|
||||
}
|
||||
|
||||
// 批量转换处理 properties 字段
|
||||
@AfterMapping
|
||||
default void convertPropertiesListToVO(List<IotThinkModelFunctionDO> sourceList, @MappingTarget List<IotThinkModelFunctionRespVO> targetList) {
|
||||
for (int i = 0; i < sourceList.size(); i++) {
|
||||
convertPropertiesToVO(sourceList.get(i), targetList.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cn.iocoder.yudao.module.iot.service.thinkmodelfunction;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*;
|
||||
import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO;
|
||||
import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert;
|
||||
import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO;
|
||||
@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY;
|
||||
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS;
|
||||
@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
|
||||
log.info("创建物模型,参数:{}", createReqVO);
|
||||
// 验证 ProductKey 对应的产品物模型是否已存在
|
||||
validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey());
|
||||
// 插入
|
||||
// 转换请求对象为数据对象
|
||||
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO);
|
||||
// 自动生成属性上报事件和属性设置、获取服务
|
||||
generateDefaultEventsAndServices(createReqVO, thinkModelFunction);
|
||||
// 插入数据库
|
||||
thinkModelFunctionMapper.insert(thinkModelFunction);
|
||||
// 返回
|
||||
// 返回生成的 ID
|
||||
return thinkModelFunction.getId();
|
||||
}
|
||||
|
||||
@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
|
||||
@Override
|
||||
public void deleteThinkModelFunction(Long id) {
|
||||
log.info("删除物模型,id:{}", id);
|
||||
// 校验存在
|
||||
// 校验物模型是否存在
|
||||
validateThinkModelFunctionExists(id);
|
||||
// 删除
|
||||
// 删除物模型
|
||||
thinkModelFunctionMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
|
||||
@Override
|
||||
public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) {
|
||||
log.info("更新物模型,参数:{}", updateReqVO);
|
||||
// 校验存在
|
||||
// 校验物模型是否存在
|
||||
validateThinkModelFunctionExists(updateReqVO.getId());
|
||||
// 校验 productKey 是否重复
|
||||
// 校验 ProductKey 是否唯一
|
||||
validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey());
|
||||
// 更新
|
||||
// 转换请求对象为数据对象
|
||||
IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO);
|
||||
// 自动生成或更新属性上报事件和属性设置、获取服务
|
||||
generateDefaultEventsAndServices(updateReqVO, thinkModelFunction);
|
||||
// 更新数据库
|
||||
thinkModelFunctionMapper.updateById(thinkModelFunction);
|
||||
}
|
||||
|
||||
@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
|
||||
throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ TODO 还要再优化
|
||||
* 根据属性列表,自动生成属性上报事件和属性设置、获取服务
|
||||
*/
|
||||
private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) {
|
||||
// 获取属性列表
|
||||
List<ThingModelProperty> properties = reqVO.getProperties();
|
||||
if (properties == null) {
|
||||
properties = new ArrayList<>();
|
||||
}
|
||||
|
||||
// 生成属性上报事件
|
||||
List<ThingModelEvent> events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>();
|
||||
ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties);
|
||||
events.add(propertyPostEvent);
|
||||
|
||||
// 生成属性设置和获取服务
|
||||
List<ThingModelService> services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>();
|
||||
ThingModelService propertySetService = generatePropertySetService(properties);
|
||||
if (propertySetService != null) {
|
||||
services.add(propertySetService);
|
||||
}
|
||||
ThingModelService propertyGetService = generatePropertyGetService(properties);
|
||||
if (propertyGetService != null) {
|
||||
services.add(propertyGetService);
|
||||
}
|
||||
|
||||
// 更新 thinkModelFunction 对象的 events 和 services 字段
|
||||
thinkModelFunction.setEvents(JSONUtil.toJsonStr(events));
|
||||
thinkModelFunction.setServices(JSONUtil.toJsonStr(services));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成属性上报事件
|
||||
*/
|
||||
private ThingModelEvent generatePropertyPostEvent(List<ThingModelProperty> properties) {
|
||||
ThingModelEvent event = new ThingModelEvent();
|
||||
event.setIdentifier("post");
|
||||
event.setName("属性上报");
|
||||
event.setType("info");
|
||||
event.setDescription("属性上报事件");
|
||||
event.setMethod("thing.event.property.post");
|
||||
|
||||
// 将属性列表转换为事件的输出参数
|
||||
List<ThingModelArgument> outputData = new ArrayList<>();
|
||||
for (ThingModelProperty property : properties) {
|
||||
ThingModelArgument arg = new ThingModelArgument();
|
||||
arg.setIdentifier(property.getIdentifier());
|
||||
arg.setName(property.getName());
|
||||
arg.setDataType(property.getDataType());
|
||||
arg.setDescription(property.getDescription());
|
||||
arg.setDirection("output"); // 设置为输出参数
|
||||
outputData.add(arg);
|
||||
}
|
||||
event.setOutputData(outputData);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成属性设置服务
|
||||
*/
|
||||
private ThingModelService generatePropertySetService(List<ThingModelProperty> properties) {
|
||||
List<ThingModelArgument> inputData = new ArrayList<>();
|
||||
for (ThingModelProperty property : properties) {
|
||||
if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
|
||||
ThingModelArgument arg = new ThingModelArgument();
|
||||
arg.setIdentifier(property.getIdentifier());
|
||||
arg.setName(property.getName());
|
||||
arg.setDataType(property.getDataType());
|
||||
arg.setDescription(property.getDescription());
|
||||
arg.setDirection("input"); // 设置为输入参数
|
||||
inputData.add(arg);
|
||||
}
|
||||
}
|
||||
if (inputData.isEmpty()) {
|
||||
// 如果没有可写属性,不生成属性设置服务
|
||||
return null;
|
||||
}
|
||||
|
||||
ThingModelService service = new ThingModelService();
|
||||
service.setIdentifier("set");
|
||||
service.setName("属性设置");
|
||||
service.setCallType("async");
|
||||
service.setDescription("属性设置服务");
|
||||
service.setMethod("thing.service.property.set");
|
||||
service.setInputData(inputData);
|
||||
// 属性设置服务一般不需要输出参数
|
||||
service.setOutputData(new ArrayList<>());
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成属性获取服务
|
||||
*/
|
||||
private ThingModelService generatePropertyGetService(List<ThingModelProperty> properties) {
|
||||
List<ThingModelArgument> outputData = new ArrayList<>();
|
||||
for (ThingModelProperty property : properties) {
|
||||
if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) {
|
||||
ThingModelArgument arg = new ThingModelArgument();
|
||||
arg.setIdentifier(property.getIdentifier());
|
||||
arg.setName(property.getName());
|
||||
arg.setDataType(property.getDataType());
|
||||
arg.setDescription(property.getDescription());
|
||||
arg.setDirection("output"); // 设置为输出参数
|
||||
outputData.add(arg);
|
||||
}
|
||||
}
|
||||
if (outputData.isEmpty()) {
|
||||
// 如果没有可读属性,不生成属性获取服务
|
||||
return null;
|
||||
}
|
||||
|
||||
ThingModelService service = new ThingModelService();
|
||||
service.setIdentifier("get");
|
||||
service.setName("属性获取");
|
||||
service.setCallType("async");
|
||||
service.setDescription("属性获取服务");
|
||||
service.setMethod("thing.service.property.get");
|
||||
|
||||
// 定义输入参数:属性标识符列表
|
||||
ThingModelArgument inputArg = new ThingModelArgument();
|
||||
inputArg.setIdentifier("properties");
|
||||
inputArg.setName("属性标识符列表");
|
||||
inputArg.setDescription("需要获取的属性标识符列表");
|
||||
inputArg.setDirection("input"); // 设置为输入参数
|
||||
|
||||
// 创建数组类型,元素类型为文本类型(字符串)
|
||||
ThingModelArrayType arrayType = new ThingModelArrayType();
|
||||
arrayType.setType("array");
|
||||
ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs();
|
||||
// 不指定数组长度,size 可以为 0 或者省略
|
||||
ThingModelTextType textType = new ThingModelTextType();
|
||||
textType.setType("text");
|
||||
// 如果有需要,可以设置 TextType 的 specs,如长度限制
|
||||
arraySpecs.setItem(textType);
|
||||
arrayType.setSpecs(arraySpecs);
|
||||
|
||||
inputArg.setDataType(arrayType);
|
||||
|
||||
service.setInputData(Collections.singletonList(inputArg));
|
||||
service.setOutputData(outputData);
|
||||
|
||||
return service;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user