perf:【IoT 物联网】场景联动触发条件属性选择器组件优化

pull/793/head
puhui999 2025-07-17 23:32:45 +08:00
parent ec94c33d85
commit f31d034c79
4 changed files with 850 additions and 87 deletions

View File

@ -0,0 +1,468 @@
# IotThingModelTSLRespVO 数据结构文档
## 概述
`IotThingModelTSLRespVO` 是IoT产品物模型TSLThing Specification Language的响应数据结构用于返回完整的产品物模型定义包括属性、事件和服务的详细信息。TSL是阿里云IoT平台定义的一套物模型描述规范。
## 主体数据结构
### IotThingModelTSLRespVO
```typescript
interface IotThingModelTSLRespVO {
productId: number; // 产品编号(必填)
productKey: string; // 产品标识(必填)
properties: ThingModelProperty[]; // 属性列表(必填)
events: ThingModelEvent[]; // 事件列表(必填)
services: ThingModelService[]; // 服务列表(必填)
}
```
**字段说明:**
- `productId`: 产品编号唯一标识一个IoT产品
- `productKey`: 产品标识符,用于设备连接和识别
- `properties`: 设备属性列表,描述设备的状态信息
- `events`: 设备事件列表,描述设备主动上报的事件
- `services`: 设备服务列表,描述可以调用的设备功能
## 属性数据结构 (ThingModelProperty)
### 基本结构
```typescript
interface ThingModelProperty {
identifier: string; // 属性标识符(必填)
name: string; // 属性名称(必填)
accessMode: string; // 访问模式(必填)
required?: boolean; // 是否必选
dataType: string; // 数据类型(必填)
dataSpecs?: ThingModelDataSpecs; // 数据规范(非列表型)
dataSpecsList?: ThingModelDataSpecs[]; // 数据规范(列表型)
}
```
### 字段详细说明
#### identifier属性标识符
- **类型**: `string`
- **必填**: 是
- **格式**: 正则表达式 `^[a-zA-Z][a-zA-Z0-9_]{0,31}$`
- **说明**: 只能由字母、数字和下划线组成必须以字母开头长度不超过32个字符
- **示例**: `"temperature"`, `"humidity"`, `"power_status"`
#### name属性名称
- **类型**: `string`
- **必填**: 是
- **说明**: 属性的显示名称,用于界面展示
- **示例**: `"温度"`, `"湿度"`, `"电源状态"`
#### accessMode访问模式
- **类型**: `string`
- **必填**: 是
- **枚举值**:
- `"r"`: 只读,设备只能上报,平台不能下发
- `"rw"`: 读写,设备可以上报,平台也可以下发
- **示例**: `"r"`, `"rw"`
#### dataType数据类型
- **类型**: `string`
- **必填**: 是
- **枚举值**:
- `"int"`: 整数型
- `"float"`: 单精度浮点型
- `"double"`: 双精度浮点型
- `"enum"`: 枚举型
- `"bool"`: 布尔型
- `"text"`: 文本型
- `"date"`: 时间型
- `"struct"`: 结构体型
- `"array"`: 数组型
## 事件数据结构 (ThingModelEvent)
### 基本结构
```typescript
interface ThingModelEvent {
identifier: string; // 事件标识符(必填)
name: string; // 事件名称(必填)
required?: boolean; // 是否必选
type: string; // 事件类型(必填)
outputParams?: ThingModelParam[]; // 输出参数
method?: string; // 执行方法
}
```
### 字段详细说明
#### type事件类型
- **类型**: `string`
- **必填**: 是
- **枚举值**:
- `"info"`: 信息事件
- `"alert"`: 告警事件
- `"error"`: 故障事件
#### outputParams输出参数
- **类型**: `ThingModelParam[]`
- **必填**: 否
- **说明**: 事件触发时返回的参数信息
## 服务数据结构 (ThingModelService)
### 基本结构
```typescript
interface ThingModelService {
identifier: string; // 服务标识符(必填)
name: string; // 服务名称(必填)
required?: boolean; // 是否必选
callType: string; // 调用类型(必填)
inputParams?: ThingModelParam[]; // 输入参数
outputParams?: ThingModelParam[]; // 输出参数
method?: string; // 执行方法
}
```
### 字段详细说明
#### callType调用类型
- **类型**: `string`
- **必填**: 是
- **枚举值**:
- `"async"`: 异步调用
- `"sync"`: 同步调用
## 参数数据结构 (ThingModelParam)
### 基本结构
```typescript
interface ThingModelParam {
identifier: string; // 参数标识符(必填)
name: string; // 参数名称(必填)
direction: string; // 参数方向(必填)
paraOrder?: number; // 参数序号
dataType: string; // 数据类型(必填)
dataSpecs?: ThingModelDataSpecs; // 数据规范(非列表型)
dataSpecsList?: ThingModelDataSpecs[]; // 数据规范(列表型)
}
```
### 字段详细说明
#### direction参数方向
- **类型**: `string`
- **必填**: 是
- **枚举值**:
- `"input"`: 输入参数
- `"output"`: 输出参数
## 数据规范结构 (ThingModelDataSpecs)
数据规范是一个抽象基类,根据不同的数据类型有不同的具体实现:
### 1. 数值型数据规范 (ThingModelNumericDataSpec)
适用于 `int`、`float`、`double` 类型:
```typescript
interface ThingModelNumericDataSpec {
dataType: "int" | "float" | "double";
max: string; // 最大值(必填)
min: string; // 最小值(必填)
step: string; // 步长(必填)
precise?: string; // 精度float/double可选
defaultValue?: string; // 默认值
unit?: string; // 单位符号
unitName?: string; // 单位名称
}
```
### 2. 布尔/枚举型数据规范 (ThingModelBoolOrEnumDataSpecs)
适用于 `bool`、`enum` 类型:
```typescript
interface ThingModelBoolOrEnumDataSpecs {
dataType: "bool" | "enum";
name: string; // 枚举项名称(必填)
value: number; // 枚举值(必填)
}
```
### 3. 文本/时间型数据规范 (ThingModelDateOrTextDataSpecs)
适用于 `text`、`date` 类型:
```typescript
interface ThingModelDateOrTextDataSpecs {
dataType: "text" | "date";
length?: number; // 数据长度text类型需要最大2048
defaultValue?: string; // 默认值
}
```
### 4. 数组型数据规范 (ThingModelArrayDataSpecs)
适用于 `array` 类型:
```typescript
interface ThingModelArrayDataSpecs {
dataType: "array";
size: number; // 数组元素个数(必填)
childDataType: string; // 数组元素数据类型(必填)
dataSpecsList?: ThingModelDataSpecs[]; // 子元素数据规范struct类型时
}
```
**childDataType 枚举值**:
- `"struct"`: 结构体
- `"int"`: 整数
- `"float"`: 单精度浮点
- `"double"`: 双精度浮点
- `"text"`: 文本
### 5. 结构体型数据规范 (ThingModelStructDataSpecs)
适用于 `struct` 类型:
```typescript
interface ThingModelStructDataSpecs {
dataType: "struct";
identifier: string; // 属性标识符(必填)
name: string; // 属性名称(必填)
accessMode: string; // 操作类型(必填)
required?: boolean; // 是否必选
childDataType: string; // 子数据类型(必填)
dataSpecs?: ThingModelDataSpecs; // 数据规范(非列表型)
dataSpecsList?: ThingModelDataSpecs[]; // 数据规范(列表型)
}
```
**childDataType 枚举值**:
- `"int"`: 整数
- `"float"`: 单精度浮点
- `"double"`: 双精度浮点
- `"text"`: 文本
- `"date"`: 时间
- `"enum"`: 枚举
- `"bool"`: 布尔
## 数据类型映射关系
### dataSpecs vs dataSpecsList
- **dataSpecs**: 用于非列表型数据类型(`int`、`float`、`double`、`text`、`date`、`array`
- **dataSpecsList**: 用于列表型数据类型(`enum`、`bool`、`struct`
### JSON多态序列化
数据规范使用Jackson的`@JsonTypeInfo`和`@JsonSubTypes`注解实现多态序列化:
```json
{
"dataType": "int",
"max": "100",
"min": "0",
"step": "1",
"unit": "°C",
"unitName": "摄氏度"
}
```
## 完整示例
### 温度传感器物模型示例
```json
{
"productId": 1024,
"productKey": "temperature_sensor",
"properties": [
{
"identifier": "temperature",
"name": "温度",
"accessMode": "r",
"required": true,
"dataType": "float",
"dataSpecs": {
"dataType": "float",
"max": "100.0",
"min": "-40.0",
"step": "0.1",
"precise": "1",
"unit": "°C",
"unitName": "摄氏度"
}
},
{
"identifier": "power_switch",
"name": "电源开关",
"accessMode": "rw",
"required": false,
"dataType": "bool",
"dataSpecsList": [
{
"dataType": "bool",
"name": "关闭",
"value": 0
},
{
"dataType": "bool",
"name": "开启",
"value": 1
}
]
}
],
"events": [
{
"identifier": "high_temperature_alert",
"name": "高温告警",
"required": false,
"type": "alert",
"outputParams": [
{
"identifier": "current_temp",
"name": "当前温度",
"direction": "output",
"dataType": "float",
"dataSpecs": {
"dataType": "float",
"max": "100.0",
"min": "-40.0",
"step": "0.1"
}
}
]
}
],
"services": [
{
"identifier": "reset_device",
"name": "重置设备",
"required": false,
"callType": "async",
"inputParams": [
{
"identifier": "reset_type",
"name": "重置类型",
"direction": "input",
"dataType": "enum",
"dataSpecsList": [
{
"dataType": "enum",
"name": "软重置",
"value": 1
},
{
"dataType": "enum",
"name": "硬重置",
"value": 2
}
]
}
],
"outputParams": [
{
"identifier": "result",
"name": "执行结果",
"direction": "output",
"dataType": "bool",
"dataSpecsList": [
{
"dataType": "bool",
"name": "失败",
"value": 0
},
{
"dataType": "bool",
"name": "成功",
"value": 1
}
]
}
]
}
]
}
```
## 前端使用建议
### 1. TypeScript类型定义
建议在前端项目中定义完整的TypeScript接口确保类型安全
```typescript
// 定义完整的类型接口
export interface IotThingModelTSLRespVO {
productId: number;
productKey: string;
properties: ThingModelProperty[];
events: ThingModelEvent[];
services: ThingModelService[];
}
// 使用联合类型处理数据规范的多态性
export type ThingModelDataSpecs =
| ThingModelNumericDataSpec
| ThingModelBoolOrEnumDataSpecs
| ThingModelDateOrTextDataSpecs
| ThingModelArrayDataSpecs
| ThingModelStructDataSpecs;
```
### 2. 数据验证
```typescript
// 验证数据类型和数据规范的一致性
function validateDataSpecs(dataType: string, dataSpecs: any): boolean {
switch (dataType) {
case 'int':
case 'float':
case 'double':
return dataSpecs.dataType === dataType &&
dataSpecs.max !== undefined &&
dataSpecs.min !== undefined;
case 'bool':
case 'enum':
return Array.isArray(dataSpecs) &&
dataSpecs.every(spec => spec.name && spec.value !== undefined);
// ... 其他类型验证
default:
return false;
}
}
```
### 3. 数据转换工具
```typescript
// 将后端数据转换为前端展示格式
function formatPropertyValue(property: ThingModelProperty, value: any): string {
if (property.dataType === 'enum' || property.dataType === 'bool') {
const spec = property.dataSpecsList?.find(s => s.value === value);
return spec?.name || String(value);
}
if (property.dataType === 'float' || property.dataType === 'double') {
const unit = property.dataSpecs?.unit || '';
return `${value}${unit}`;
}
return String(value);
}
```
## 注意事项
1. **数据规范选择**: 根据`dataType`选择使用`dataSpecs`还是`dataSpecsList`
2. **标识符唯一性**: 在同一产品下,所有功能的`identifier`必须唯一
3. **数据类型一致性**: 参数的`dataType`必须与其`dataSpecs`的`dataType`保持一致
4. **枚举值处理**: 布尔型和枚举型数据使用`dataSpecsList`数组存储可选值
5. **嵌套结构**: 结构体和数组类型可能包含嵌套的数据规范定义
6. **版本兼容**: 物模型结构可能随版本演进,前端需要做好兼容性处理
这个数据结构为IoT设备的完整功能描述提供了标准化的格式支持复杂的数据类型和嵌套结构能够满足各种IoT设备的建模需求。

View File

@ -34,8 +34,20 @@
</el-form-item>
</el-col>
<!-- 设备选择 -->
<!-- 设备选择模式 -->
<el-col :span="12">
<el-form-item label="设备选择模式" required>
<el-radio-group v-model="deviceSelectionMode" @change="handleDeviceSelectionModeChange">
<el-radio value="specific">选择设备</el-radio>
<el-radio value="all">全部设备</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- 具体设备选择 -->
<el-row v-if="deviceSelectionMode === 'specific'" :gutter="16">
<el-col :span="24">
<el-form-item label="选择设备" required>
<el-select
v-model="localDeviceId"
@ -58,8 +70,8 @@
<div class="option-name">{{ device.deviceName }}</div>
<div class="option-nickname">{{ device.nickname || '无备注' }}</div>
</div>
<el-tag
size="small"
<el-tag
size="small"
:type="getDeviceStatusTag(device.state)"
>
{{ getDeviceStatusText(device.state) }}
@ -72,7 +84,7 @@
</el-row>
<!-- 选择结果展示 -->
<div v-if="localProductId && localDeviceId" class="selection-result">
<div v-if="localProductId && (localDeviceId !== undefined)" class="selection-result">
<div class="result-header">
<Icon icon="ep:check" class="result-icon" />
<span class="result-title">已选择设备</span>
@ -85,9 +97,18 @@
</div>
<div class="result-item">
<span class="result-label">设备</span>
<span class="result-value">{{ selectedDevice?.deviceName }}</span>
<el-tag
size="small"
<span v-if="deviceSelectionMode === 'all'" class="result-value"></span>
<span v-else class="result-value">{{ selectedDevice?.deviceName }}</span>
<el-tag
v-if="deviceSelectionMode === 'all'"
size="small"
type="warning"
>
全部
</el-tag>
<el-tag
v-else
size="small"
:type="getDeviceStatusTag(selectedDevice?.state)"
>
{{ getDeviceStatusText(selectedDevice?.state) }}
@ -123,6 +144,9 @@ const emit = defineEmits<Emits>()
const localProductId = useVModel(props, 'productId', emit)
const localDeviceId = useVModel(props, 'deviceId', emit)
//
const deviceSelectionMode = ref<'specific' | 'all'>('specific')
//
const productLoading = ref(false)
const deviceLoading = ref(false)
@ -162,11 +186,11 @@ const handleProductChange = async (productId?: number) => {
localProductId.value = productId
localDeviceId.value = undefined
deviceList.value = []
if (productId) {
await getDeviceList(productId)
}
emitChange()
}
@ -175,6 +199,20 @@ const handleDeviceChange = (deviceId?: number) => {
emitChange()
}
const handleDeviceSelectionModeChange = (mode: 'specific' | 'all') => {
deviceSelectionMode.value = mode
if (mode === 'all') {
// ID0
localDeviceId.value = 0
} else {
// ID
localDeviceId.value = undefined
}
emitChange()
}
const emitChange = () => {
emit('change', {
productId: localProductId.value,
@ -222,7 +260,14 @@ const getDeviceList = async (productId: number) => {
//
onMounted(async () => {
await getProductList()
// ID
if (localDeviceId.value === 0) {
deviceSelectionMode.value = 'all'
} else if (localDeviceId.value) {
deviceSelectionMode.value = 'specific'
}
if (localProductId.value) {
await getDeviceList(localProductId.value)
}

View File

@ -27,8 +27,8 @@
<div class="option-identifier">{{ property.identifier }}</div>
</div>
<div class="option-meta">
<el-tag :type="getPropertyTypeTag(property.type)" size="small">
{{ getPropertyTypeName(property.type) }}
<el-tag :type="getPropertyTypeTag(property.dataType)" size="small">
{{ getPropertyTypeName(property.dataType) }}
</el-tag>
</div>
</div>
@ -41,8 +41,8 @@
<div class="details-header">
<Icon icon="ep:info-filled" class="details-icon" />
<span class="details-title">{{ selectedProperty.name }}</span>
<el-tag :type="getPropertyTypeTag(selectedProperty.type)" size="small">
{{ getPropertyTypeName(selectedProperty.type) }}
<el-tag :type="getPropertyTypeTag(selectedProperty.dataType)" size="small">
{{ getPropertyTypeName(selectedProperty.dataType) }}
</el-tag>
</div>
<div class="details-content">
@ -70,6 +70,9 @@
<script setup lang="ts">
import { useVModel } from '@vueuse/core'
import { IotRuleSceneTriggerTypeEnum } from '@/api/iot/rule/scene/scene.types'
import { ThingModelApi, ThingModelData } from '@/api/iot/thingmodel'
import { IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
import type { IotThingModelTSLRespVO, PropertySelectorItem } from './types'
/** 属性选择器组件 */
defineOptions({ name: 'PropertySelector' })
@ -93,33 +96,34 @@ const localValue = useVModel(props, 'modelValue', emit)
//
const loading = ref(false)
const propertyList = ref<any[]>([])
const propertyList = ref<PropertySelectorItem[]>([])
const thingModelTSL = ref<IotThingModelTSLRespVO | null>(null)
//
const propertyGroups = computed(() => {
const groups: { label: string; options: any[] }[] = []
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST) {
groups.push({
label: '设备属性',
options: propertyList.value.filter(p => p.category === 'property')
options: propertyList.value.filter(p => p.type === IoTThingModelTypeEnum.PROPERTY)
})
}
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST) {
groups.push({
label: '设备事件',
options: propertyList.value.filter(p => p.category === 'event')
options: propertyList.value.filter(p => p.type === IoTThingModelTypeEnum.EVENT)
})
}
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
groups.push({
label: '设备服务',
options: propertyList.value.filter(p => p.category === 'service')
options: propertyList.value.filter(p => p.type === IoTThingModelTypeEnum.SERVICE)
})
}
return groups.filter(group => group.options.length > 0)
})
@ -128,34 +132,34 @@ const selectedProperty = computed(() => {
})
//
const getPropertyTypeName = (type: string) => {
const getPropertyTypeName = (dataType: string) => {
const typeMap = {
'int': '整数',
'float': '浮点数',
'double': '双精度',
'string': '字符串',
'text': '字符串',
'bool': '布尔值',
'enum': '枚举',
'date': '日期',
'struct': '结构体',
'array': '数组'
}
return typeMap[type] || type
return typeMap[dataType] || dataType
}
const getPropertyTypeTag = (type: string) => {
const getPropertyTypeTag = (dataType: string) => {
const tagMap = {
'int': 'primary',
'float': 'success',
'double': 'success',
'string': 'info',
'text': 'info',
'bool': 'warning',
'enum': 'danger',
'date': 'primary',
'struct': 'info',
'array': 'warning'
}
return tagMap[type] || 'info'
return tagMap[dataType] || 'info'
}
//
@ -163,84 +167,162 @@ const handleChange = (value: string) => {
const property = propertyList.value.find(p => p.identifier === value)
if (property) {
emit('change', {
type: property.type,
type: property.dataType,
config: property
})
}
}
// API
const getPropertyList = async () => {
// TSL
const getThingModelTSL = async () => {
if (!props.productId) {
thingModelTSL.value = null
propertyList.value = []
return
}
loading.value = true
try {
// API
// 使
propertyList.value = [
//
{
identifier: 'temperature',
name: '温度',
type: 'float',
category: 'property',
description: '环境温度',
unit: '°C',
range: '-40~80'
},
{
identifier: 'humidity',
name: '湿度',
type: 'float',
category: 'property',
description: '环境湿度',
unit: '%',
range: '0~100'
},
{
identifier: 'power',
name: '电源状态',
type: 'bool',
category: 'property',
description: '设备电源开关状态'
},
//
{
identifier: 'alarm',
name: '告警事件',
type: 'struct',
category: 'event',
description: '设备告警事件'
},
{
identifier: 'fault',
name: '故障事件',
type: 'struct',
category: 'event',
description: '设备故障事件'
},
//
{
identifier: 'restart',
name: '重启服务',
type: 'struct',
category: 'service',
description: '设备重启服务'
}
]
thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(props.productId)
parseThingModelData()
} catch (error) {
console.error('获取物模型失败:', error)
console.error('获取物模型TSL失败:', error)
// TSL
await getThingModelList()
} finally {
loading.value = false
}
}
//
const getThingModelList = async () => {
if (!props.productId) {
propertyList.value = []
return
}
try {
const data = await ThingModelApi.getThingModelList({ productId: props.productId })
propertyList.value = data || []
} catch (error) {
console.error('获取物模型列表失败:', error)
propertyList.value = []
}
}
// TSL
const parseThingModelData = () => {
const tsl = thingModelTSL.value
const properties: PropertySelectorItem[] = []
if (tsl) {
//
if (tsl.properties && Array.isArray(tsl.properties)) {
tsl.properties.forEach((prop) => {
properties.push({
identifier: prop.identifier,
name: prop.name,
description: prop.description,
dataType: prop.dataType,
type: IoTThingModelTypeEnum.PROPERTY,
accessMode: prop.accessMode,
required: prop.required,
unit: getPropertyUnit(prop),
range: getPropertyRange(prop),
property: prop
})
})
}
//
if (tsl.events && Array.isArray(tsl.events)) {
tsl.events.forEach((event) => {
properties.push({
identifier: event.identifier,
name: event.name,
description: event.description,
dataType: 'struct',
type: IoTThingModelTypeEnum.EVENT,
eventType: event.type,
required: event.required,
outputParams: event.outputParams,
event: event
})
})
}
//
if (tsl.services && Array.isArray(tsl.services)) {
tsl.services.forEach((service) => {
properties.push({
identifier: service.identifier,
name: service.name,
description: service.description,
dataType: 'struct',
type: IoTThingModelTypeEnum.SERVICE,
callType: service.callType,
required: service.required,
inputParams: service.inputParams,
outputParams: service.outputParams,
service: service
})
})
}
}
propertyList.value = properties
}
//
const getPropertyUnit = (property: any) => {
if (!property) return undefined
//
if (property.dataSpecs && property.dataSpecs.unit) {
return property.dataSpecs.unit
}
return undefined
}
//
const getPropertyRange = (property: any) => {
if (!property) return undefined
//
if (property.dataSpecs) {
const specs = property.dataSpecs
if (specs.min !== undefined && specs.max !== undefined) {
return `${specs.min}~${specs.max}`
}
}
//
if (property.dataSpecsList && Array.isArray(property.dataSpecsList)) {
return property.dataSpecsList.map((item: any) => `${item.name}(${item.value})`).join(', ')
}
return undefined
}
//
const getDataRange = (dataSpecs: any) => {
if (!dataSpecs) return undefined
if (dataSpecs.min !== undefined && dataSpecs.max !== undefined) {
return `${dataSpecs.min}~${dataSpecs.max}`
}
if (dataSpecs.dataSpecsList && Array.isArray(dataSpecs.dataSpecsList)) {
return dataSpecs.dataSpecsList.map((item: any) => `${item.name}(${item.value})`).join(', ')
}
return undefined
}
//
watch(() => props.productId, () => {
getPropertyList()
getThingModelTSL()
}, { immediate: true })
//

View File

@ -0,0 +1,168 @@
// IoT物模型TSL数据类型定义
/** 物模型TSL响应数据结构 */
export interface IotThingModelTSLRespVO {
productId: number
productKey: string
properties: ThingModelProperty[]
events: ThingModelEvent[]
services: ThingModelService[]
}
/** 物模型属性 */
export interface ThingModelProperty {
identifier: string
name: string
accessMode: string
required?: boolean
dataType: string
description?: string
dataSpecs?: ThingModelDataSpecs
dataSpecsList?: ThingModelDataSpecs[]
}
/** 物模型事件 */
export interface ThingModelEvent {
identifier: string
name: string
required?: boolean
type: string
description?: string
outputParams?: ThingModelParam[]
method?: string
}
/** 物模型服务 */
export interface ThingModelService {
identifier: string
name: string
required?: boolean
callType: string
description?: string
inputParams?: ThingModelParam[]
outputParams?: ThingModelParam[]
method?: string
}
/** 物模型参数 */
export interface ThingModelParam {
identifier: string
name: string
direction: string
paraOrder?: number
dataType: string
dataSpecs?: ThingModelDataSpecs
dataSpecsList?: ThingModelDataSpecs[]
}
/** 数值型数据规范 */
export interface ThingModelNumericDataSpec {
dataType: 'int' | 'float' | 'double'
max: string
min: string
step: string
precise?: string
defaultValue?: string
unit?: string
unitName?: string
}
/** 布尔/枚举型数据规范 */
export interface ThingModelBoolOrEnumDataSpecs {
dataType: 'bool' | 'enum'
name: string
value: number
}
/** 文本/时间型数据规范 */
export interface ThingModelDateOrTextDataSpecs {
dataType: 'text' | 'date'
length?: number
defaultValue?: string
}
/** 数组型数据规范 */
export interface ThingModelArrayDataSpecs {
dataType: 'array'
size: number
childDataType: string
dataSpecsList?: ThingModelDataSpecs[]
}
/** 结构体型数据规范 */
export interface ThingModelStructDataSpecs {
dataType: 'struct'
identifier: string
name: string
accessMode: string
required?: boolean
childDataType: string
dataSpecs?: ThingModelDataSpecs
dataSpecsList?: ThingModelDataSpecs[]
}
/** 数据规范联合类型 */
export type ThingModelDataSpecs =
| ThingModelNumericDataSpec
| ThingModelBoolOrEnumDataSpecs
| ThingModelDateOrTextDataSpecs
| ThingModelArrayDataSpecs
| ThingModelStructDataSpecs
/** 属性选择器内部使用的统一数据结构 */
export interface PropertySelectorItem {
identifier: string
name: string
description?: string
dataType: string
type: number // IoTThingModelTypeEnum
accessMode?: string
required?: boolean
unit?: string
range?: string
eventType?: string
callType?: string
inputParams?: ThingModelParam[]
outputParams?: ThingModelParam[]
property?: ThingModelProperty
event?: ThingModelEvent
service?: ThingModelService
}
/** 数据类型枚举 */
export enum DataTypeEnum {
INT = 'int',
FLOAT = 'float',
DOUBLE = 'double',
ENUM = 'enum',
BOOL = 'bool',
TEXT = 'text',
DATE = 'date',
STRUCT = 'struct',
ARRAY = 'array'
}
/** 访问模式枚举 */
export enum AccessModeEnum {
READ = 'r',
READ_write = 'rw'
}
/** 事件类型枚举 */
export enum EventTypeEnum {
INFO = 'info',
ALERT = 'alert',
ERROR = 'error'
}
/** 调用类型枚举 */
export enum CallTypeEnum {
ASYNC = 'async',
SYNC = 'sync'
}
/** 参数方向枚举 */
export enum ParamDirectionEnum {
INPUT = 'input',
OUTPUT = 'output'
}