fix(ts): 收尾 IOT 物模型类型,ts:check 清零
- 去掉 ThingModelProperty/Event/Service 重复空接口,dataSpecs 建为通用联合类型 - dataSpecsList 支持结构体/枚举/布尔项,补齐枚举项 identifier/accessMode - 物模型表单编辑态用类型断言;DataDefinition/ThingModelProperty 对动态 dataSpecs 安全访问 - 场景规则动态字段改用 Object.assign,规避 keyof 写入被推成 never Co-Authored-By: Codex <codex@openai.com> ts:check 26 → 0master
parent
983ac71559
commit
69444994ad
|
|
@ -18,47 +18,35 @@ export interface ThingModelData {
|
||||||
service?: ThingModelService // 服务
|
service?: ThingModelService // 服务
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ThingModelProperty 类型
|
|
||||||
*/
|
|
||||||
export interface ThingModelProperty {
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ThingModelEvent 类型
|
|
||||||
*/
|
|
||||||
export interface ThingModelEvent {
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ThingModelService 类型
|
|
||||||
*/
|
|
||||||
export interface ThingModelService {
|
|
||||||
[key: string]: any
|
|
||||||
}
|
|
||||||
|
|
||||||
/** dataSpecs 数值型数据结构 */
|
/** dataSpecs 数值型数据结构 */
|
||||||
export interface DataSpecsNumberData {
|
export interface DataSpecsNumberData {
|
||||||
dataType: 'int' | 'float' | 'double' // 数据类型,取值为 INT、FLOAT 或 DOUBLE
|
dataType: string // 数据类型,取值为 INT、FLOAT 或 DOUBLE
|
||||||
max: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
|
max?: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
|
||||||
min: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
|
min?: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
|
||||||
step: string // 步长,必须与 dataType 设置一致,且为 STRING 类型
|
step?: string // 步长,必须与 dataType 设置一致,且为 STRING 类型
|
||||||
precise?: string // 精度,当 dataType 为 FLOAT 或 DOUBLE 时可选
|
precise?: string // 精度,当 dataType 为 FLOAT 或 DOUBLE 时可选
|
||||||
defaultValue?: string // 默认值,可选
|
defaultValue?: string // 默认值,可选
|
||||||
unit: string // 单位的符号
|
unit?: string // 单位的符号
|
||||||
unitName: string // 单位的名称
|
unitName?: string // 单位的名称
|
||||||
}
|
}
|
||||||
|
|
||||||
/** dataSpecs 枚举型数据结构 */
|
/** dataSpecs 枚举型数据结构 */
|
||||||
export interface DataSpecsEnumOrBoolData {
|
export interface DataSpecsEnumOrBoolData {
|
||||||
dataType: 'enum' | 'bool'
|
dataType: string
|
||||||
defaultValue?: string // 默认值,可选
|
defaultValue?: string // 默认值,可选
|
||||||
name: string // 枚举项的名称
|
name: string // 枚举项的名称
|
||||||
value: number | undefined // 枚举值
|
value: number | undefined // 枚举值
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** dataSpecs 通用数据结构 */
|
||||||
|
export type ThingModelDataSpecs =
|
||||||
|
| DataSpecsNumberData
|
||||||
|
| DataSpecsEnumOrBoolData
|
||||||
|
| ThingModelDateOrTextDataSpecs
|
||||||
|
| ThingModelArrayDataSpecs
|
||||||
|
| ThingModelStructDataSpecs
|
||||||
|
| Record<string, any>
|
||||||
|
|
||||||
/** 物模型TSL响应数据结构 */
|
/** 物模型TSL响应数据结构 */
|
||||||
export interface IotThingModelTSLResp {
|
export interface IotThingModelTSLResp {
|
||||||
productId: number
|
productId: number
|
||||||
|
|
@ -76,8 +64,9 @@ export interface ThingModelProperty {
|
||||||
required?: boolean
|
required?: boolean
|
||||||
dataType: string
|
dataType: string
|
||||||
description?: string
|
description?: string
|
||||||
dataSpecs?: ThingModelProperty
|
dataSpecs?: ThingModelDataSpecs
|
||||||
dataSpecsList?: ThingModelProperty[]
|
dataSpecsList?: ThingModelPropertyDataSpecs[]
|
||||||
|
value?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 物模型事件 */
|
/** 物模型事件 */
|
||||||
|
|
@ -110,8 +99,8 @@ export interface ThingModelParam {
|
||||||
direction: string
|
direction: string
|
||||||
paraOrder?: number
|
paraOrder?: number
|
||||||
dataType: string
|
dataType: string
|
||||||
dataSpecs?: ThingModelProperty
|
dataSpecs?: ThingModelDataSpecs
|
||||||
dataSpecsList?: ThingModelProperty[]
|
dataSpecsList?: ThingModelPropertyDataSpecs[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 数值型数据规范 */
|
/** 数值型数据规范 */
|
||||||
|
|
@ -142,24 +131,26 @@ export interface ThingModelDateOrTextDataSpecs {
|
||||||
|
|
||||||
/** 数组型数据规范 */
|
/** 数组型数据规范 */
|
||||||
export interface ThingModelArrayDataSpecs {
|
export interface ThingModelArrayDataSpecs {
|
||||||
dataType: 'array'
|
dataType: string
|
||||||
size: number
|
size?: number
|
||||||
childDataType: string
|
childDataType?: string
|
||||||
dataSpecsList?: ThingModelProperty[]
|
dataSpecsList?: ThingModelPropertyDataSpecs[]
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 结构体型数据规范 */
|
/** 结构体型数据规范 */
|
||||||
export interface ThingModelStructDataSpecs {
|
export interface ThingModelStructDataSpecs {
|
||||||
dataType: 'struct'
|
dataType: string
|
||||||
identifier: string
|
identifier?: string
|
||||||
name: string
|
name?: string
|
||||||
accessMode: string
|
accessMode?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
childDataType: string
|
childDataType?: string
|
||||||
dataSpecs?: ThingModelProperty
|
dataSpecs?: ThingModelDataSpecs
|
||||||
dataSpecsList?: ThingModelProperty[]
|
dataSpecsList?: ThingModelPropertyDataSpecs[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ThingModelPropertyDataSpecs = ThingModelProperty | DataSpecsEnumOrBoolData
|
||||||
|
|
||||||
// IoT 产品物模型 API
|
// IoT 产品物模型 API
|
||||||
export const ThingModelApi = {
|
export const ThingModelApi = {
|
||||||
// 查询产品物模型分页
|
// 查询产品物模型分页
|
||||||
|
|
|
||||||
|
|
@ -189,7 +189,7 @@ const timeValue2 = computed(() => {
|
||||||
* @param value 字段值
|
* @param value 字段值
|
||||||
*/
|
*/
|
||||||
const updateConditionField = (field: keyof TriggerCondition, value: any) => {
|
const updateConditionField = (field: keyof TriggerCondition, value: any) => {
|
||||||
condition.value[field] = value
|
Object.assign(condition.value, { [field]: value })
|
||||||
emit('field-change', field)
|
emit('field-change', field)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ const ensureDeviceStatusDefaults = () => {
|
||||||
* @param value 字段值
|
* @param value 字段值
|
||||||
*/
|
*/
|
||||||
const updateConditionField = (field: keyof Trigger, value: any) => {
|
const updateConditionField = (field: keyof Trigger, value: any) => {
|
||||||
condition.value[field] = value
|
Object.assign(condition.value, { [field]: value })
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
innerFormRef.value?.validateField(field as string).catch(() => {})
|
innerFormRef.value?.validateField(field as string).catch(() => {})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,14 @@ import { ProductVO } from '@/api/iot/product/product'
|
||||||
import ThingModelProperty from './ThingModelProperty.vue'
|
import ThingModelProperty from './ThingModelProperty.vue'
|
||||||
import ThingModelService from './ThingModelService.vue'
|
import ThingModelService from './ThingModelService.vue'
|
||||||
import ThingModelEvent from './ThingModelEvent.vue'
|
import ThingModelEvent from './ThingModelEvent.vue'
|
||||||
import { ThingModelApi, ThingModelData, ThingModelFormRules } from '@/api/iot/thingmodel'
|
import {
|
||||||
|
ThingModelApi,
|
||||||
|
ThingModelData,
|
||||||
|
ThingModelEvent as IotThingModelEvent,
|
||||||
|
ThingModelFormRules,
|
||||||
|
ThingModelProperty as IotThingModelProperty,
|
||||||
|
ThingModelService as IotThingModelService
|
||||||
|
} from '@/api/iot/thingmodel'
|
||||||
import {
|
import {
|
||||||
IOT_PROVIDE_KEY,
|
IOT_PROVIDE_KEY,
|
||||||
IoTDataSpecsDataTypeEnum,
|
IoTDataSpecsDataTypeEnum,
|
||||||
|
|
@ -93,9 +100,9 @@ const formData = ref<ThingModelData>({
|
||||||
dataSpecs: {
|
dataSpecs: {
|
||||||
dataType: IoTDataSpecsDataTypeEnum.INT
|
dataType: IoTDataSpecsDataTypeEnum.INT
|
||||||
}
|
}
|
||||||
},
|
} as IotThingModelProperty,
|
||||||
service: {},
|
service: {} as IotThingModelService,
|
||||||
event: {}
|
event: {} as IotThingModelEvent
|
||||||
})
|
})
|
||||||
|
|
||||||
const formRef = ref() // 表单 Ref
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
@ -118,20 +125,23 @@ const open = async (type: string, id?: number) => {
|
||||||
dataSpecs: {
|
dataSpecs: {
|
||||||
dataType: IoTDataSpecsDataTypeEnum.INT
|
dataType: IoTDataSpecsDataTypeEnum.INT
|
||||||
}
|
}
|
||||||
}
|
} as IotThingModelProperty
|
||||||
}
|
}
|
||||||
// 情况二:服务初始化
|
// 情况二:服务初始化
|
||||||
if (isEmpty(formData.value.service)) {
|
if (isEmpty(formData.value.service)) {
|
||||||
formData.value.service = { inputParams: [], outputParams: [] }
|
formData.value.service = {
|
||||||
|
inputParams: [],
|
||||||
|
outputParams: []
|
||||||
|
} as unknown as IotThingModelService
|
||||||
} else {
|
} else {
|
||||||
formData.value.service.inputParams ??= []
|
formData.value.service!.inputParams ??= []
|
||||||
formData.value.service.outputParams ??= []
|
formData.value.service!.outputParams ??= []
|
||||||
}
|
}
|
||||||
// 情况三:事件初始化
|
// 情况三:事件初始化
|
||||||
if (isEmpty(formData.value.event)) {
|
if (isEmpty(formData.value.event)) {
|
||||||
formData.value.event = { outputParams: [] }
|
formData.value.event = { outputParams: [] } as unknown as IotThingModelEvent
|
||||||
} else {
|
} else {
|
||||||
formData.value.event.outputParams ??= []
|
formData.value.event!.outputParams ??= []
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
formLoading.value = false
|
formLoading.value = false
|
||||||
|
|
@ -217,9 +227,9 @@ const resetForm = () => {
|
||||||
dataSpecs: {
|
dataSpecs: {
|
||||||
dataType: IoTDataSpecsDataTypeEnum.INT
|
dataType: IoTDataSpecsDataTypeEnum.INT
|
||||||
}
|
}
|
||||||
},
|
} as IotThingModelProperty,
|
||||||
service: {},
|
service: {} as IotThingModelService,
|
||||||
event: {}
|
event: {} as IotThingModelEvent
|
||||||
}
|
}
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
IoTDataSpecsDataTypeEnum.INT,
|
IoTDataSpecsDataTypeEnum.INT,
|
||||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||||
IoTDataSpecsDataTypeEnum.FLOAT
|
IoTDataSpecsDataTypeEnum.FLOAT
|
||||||
].includes(property.dataType || '')
|
].includes(property.dataType as any)
|
||||||
"
|
"
|
||||||
v-model="property.dataSpecs"
|
v-model="property.dataSpecs"
|
||||||
/>
|
/>
|
||||||
|
|
@ -60,7 +60,11 @@
|
||||||
label="数据长度"
|
label="数据长度"
|
||||||
prop="property.dataSpecs.length"
|
prop="property.dataSpecs.length"
|
||||||
>
|
>
|
||||||
<el-input v-model="property.dataSpecs.length" class="w-255px!" placeholder="请输入文本字节长度">
|
<el-input
|
||||||
|
v-model="property.dataSpecs!['length']"
|
||||||
|
class="w-255px!"
|
||||||
|
placeholder="请输入文本字节长度"
|
||||||
|
>
|
||||||
<template #append>字节</template>
|
<template #append>字节</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -134,7 +138,7 @@ const handleChange = (dataType: any) => {
|
||||||
IoTDataSpecsDataTypeEnum.ENUM,
|
IoTDataSpecsDataTypeEnum.ENUM,
|
||||||
IoTDataSpecsDataTypeEnum.BOOL,
|
IoTDataSpecsDataTypeEnum.BOOL,
|
||||||
IoTDataSpecsDataTypeEnum.STRUCT
|
IoTDataSpecsDataTypeEnum.STRUCT
|
||||||
].includes(dataType) && (property.value.dataSpecs.dataType = dataType)
|
].includes(dataType) && (property.value.dataSpecs!.dataType = dataType)
|
||||||
switch (dataType) {
|
switch (dataType) {
|
||||||
case IoTDataSpecsDataTypeEnum.ENUM:
|
case IoTDataSpecsDataTypeEnum.ENUM:
|
||||||
property.value.dataSpecsList.push({
|
property.value.dataSpecsList.push({
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,16 @@
|
||||||
IoTDataSpecsDataTypeEnum.INT,
|
IoTDataSpecsDataTypeEnum.INT,
|
||||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||||
IoTDataSpecsDataTypeEnum.FLOAT
|
IoTDataSpecsDataTypeEnum.FLOAT
|
||||||
].includes(data.property.dataType)
|
].includes(data.property.dataType as any)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
取值范围:{{ `${data.property.dataSpecs.min}~${data.property.dataSpecs.max}` }}
|
取值范围:{{
|
||||||
|
`${getDataSpecsValue(data.property, 'min')}~${getDataSpecsValue(data.property, 'max')}`
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<!-- 非列表型:文本 -->
|
<!-- 非列表型:文本 -->
|
||||||
<div v-if="IoTDataSpecsDataTypeEnum.TEXT === data.property.dataType">
|
<div v-if="IoTDataSpecsDataTypeEnum.TEXT === data.property.dataType">
|
||||||
数据长度:{{ data.property.dataSpecs.length }}
|
数据长度:{{ getDataSpecsValue(data.property, 'length') }}
|
||||||
</div>
|
</div>
|
||||||
<!-- 列表型: 数组、结构、时间(特殊) -->
|
<!-- 列表型: 数组、结构、时间(特殊) -->
|
||||||
<div
|
<div
|
||||||
|
|
@ -24,7 +26,7 @@
|
||||||
IoTDataSpecsDataTypeEnum.ARRAY,
|
IoTDataSpecsDataTypeEnum.ARRAY,
|
||||||
IoTDataSpecsDataTypeEnum.STRUCT,
|
IoTDataSpecsDataTypeEnum.STRUCT,
|
||||||
IoTDataSpecsDataTypeEnum.DATE
|
IoTDataSpecsDataTypeEnum.DATE
|
||||||
].includes(data.property.dataType)
|
].includes(data.property.dataType as any)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
-
|
-
|
||||||
|
|
@ -32,7 +34,7 @@
|
||||||
<!-- 列表型: 布尔值、枚举 -->
|
<!-- 列表型: 布尔值、枚举 -->
|
||||||
<div
|
<div
|
||||||
v-if="
|
v-if="
|
||||||
[IoTDataSpecsDataTypeEnum.BOOL, IoTDataSpecsDataTypeEnum.ENUM].includes(
|
([IoTDataSpecsDataTypeEnum.BOOL, IoTDataSpecsDataTypeEnum.ENUM] as string[]).includes(
|
||||||
data.property.dataType
|
data.property.dataType
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|
@ -40,7 +42,7 @@
|
||||||
<div>
|
<div>
|
||||||
{{ IoTDataSpecsDataTypeEnum.BOOL === data.property.dataType ? '布尔值' : '枚举值' }}:
|
{{ IoTDataSpecsDataTypeEnum.BOOL === data.property.dataType ? '布尔值' : '枚举值' }}:
|
||||||
</div>
|
</div>
|
||||||
<div v-for="item in data.property.dataSpecsList" :key="item.value">
|
<div v-for="item in data.property.dataSpecsList || []" :key="item.value">
|
||||||
{{ `${item.name}-${item.value}` }}
|
{{ `${item.name}-${item.value}` }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -56,7 +58,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ThingModelData } from '@/api/iot/thingmodel'
|
import { ThingModelData, ThingModelProperty } from '@/api/iot/thingmodel'
|
||||||
import {
|
import {
|
||||||
getEventTypeLabel,
|
getEventTypeLabel,
|
||||||
getThingModelServiceCallTypeLabel,
|
getThingModelServiceCallTypeLabel,
|
||||||
|
|
@ -68,6 +70,10 @@ import {
|
||||||
defineOptions({ name: 'DataDefinition' })
|
defineOptions({ name: 'DataDefinition' })
|
||||||
|
|
||||||
defineProps<{ data: ThingModelData }>()
|
defineProps<{ data: ThingModelData }>()
|
||||||
|
|
||||||
|
const getDataSpecsValue = (property: ThingModelProperty, key: string) => {
|
||||||
|
return property.dataSpecs?.[key]
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue