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 → 0
master
YunaiV 2026-06-21 07:06:20 -07:00
parent 983ac71559
commit 69444994ad
6 changed files with 79 additions and 68 deletions

View File

@ -18,47 +18,35 @@ export interface ThingModelData {
service?: ThingModelService // 服务
}
/**
* ThingModelProperty
*/
export interface ThingModelProperty {
[key: string]: any
}
/**
* ThingModelEvent
*/
export interface ThingModelEvent {
[key: string]: any
}
/**
* ThingModelService
*/
export interface ThingModelService {
[key: string]: any
}
/** dataSpecs 数值型数据结构 */
export interface DataSpecsNumberData {
dataType: 'int' | 'float' | 'double' // 数据类型,取值为 INT、FLOAT 或 DOUBLE
max: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
min: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
step: string // 步长,必须与 dataType 设置一致,且为 STRING 类型
dataType: string // 数据类型,取值为 INT、FLOAT 或 DOUBLE
max?: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
min?: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
step?: string // 步长,必须与 dataType 设置一致,且为 STRING 类型
precise?: string // 精度,当 dataType 为 FLOAT 或 DOUBLE 时可选
defaultValue?: string // 默认值,可选
unit: string // 单位的符号
unitName: string // 单位的名称
unit?: string // 单位的符号
unitName?: string // 单位的名称
}
/** dataSpecs 枚举型数据结构 */
export interface DataSpecsEnumOrBoolData {
dataType: 'enum' | 'bool'
dataType: string
defaultValue?: string // 默认值,可选
name: string // 枚举项的名称
value: number | undefined // 枚举值
}
/** dataSpecs 通用数据结构 */
export type ThingModelDataSpecs =
| DataSpecsNumberData
| DataSpecsEnumOrBoolData
| ThingModelDateOrTextDataSpecs
| ThingModelArrayDataSpecs
| ThingModelStructDataSpecs
| Record<string, any>
/** 物模型TSL响应数据结构 */
export interface IotThingModelTSLResp {
productId: number
@ -76,8 +64,9 @@ export interface ThingModelProperty {
required?: boolean
dataType: string
description?: string
dataSpecs?: ThingModelProperty
dataSpecsList?: ThingModelProperty[]
dataSpecs?: ThingModelDataSpecs
dataSpecsList?: ThingModelPropertyDataSpecs[]
value?: number
}
/** 物模型事件 */
@ -110,8 +99,8 @@ export interface ThingModelParam {
direction: string
paraOrder?: number
dataType: string
dataSpecs?: ThingModelProperty
dataSpecsList?: ThingModelProperty[]
dataSpecs?: ThingModelDataSpecs
dataSpecsList?: ThingModelPropertyDataSpecs[]
}
/** 数值型数据规范 */
@ -142,24 +131,26 @@ export interface ThingModelDateOrTextDataSpecs {
/** 数组型数据规范 */
export interface ThingModelArrayDataSpecs {
dataType: 'array'
size: number
childDataType: string
dataSpecsList?: ThingModelProperty[]
dataType: string
size?: number
childDataType?: string
dataSpecsList?: ThingModelPropertyDataSpecs[]
}
/** 结构体型数据规范 */
export interface ThingModelStructDataSpecs {
dataType: 'struct'
identifier: string
name: string
accessMode: string
dataType: string
identifier?: string
name?: string
accessMode?: string
required?: boolean
childDataType: string
dataSpecs?: ThingModelProperty
dataSpecsList?: ThingModelProperty[]
childDataType?: string
dataSpecs?: ThingModelDataSpecs
dataSpecsList?: ThingModelPropertyDataSpecs[]
}
export type ThingModelPropertyDataSpecs = ThingModelProperty | DataSpecsEnumOrBoolData
// IoT 产品物模型 API
export const ThingModelApi = {
// 查询产品物模型分页

View File

@ -189,7 +189,7 @@ const timeValue2 = computed(() => {
* @param value 字段值
*/
const updateConditionField = (field: keyof TriggerCondition, value: any) => {
condition.value[field] = value
Object.assign(condition.value, { [field]: value })
emit('field-change', field)
}

View File

@ -313,7 +313,7 @@ const ensureDeviceStatusDefaults = () => {
* @param value 字段值
*/
const updateConditionField = (field: keyof Trigger, value: any) => {
condition.value[field] = value
Object.assign(condition.value, { [field]: value })
nextTick(() => {
innerFormRef.value?.validateField(field as string).catch(() => {})
})

View File

@ -63,7 +63,14 @@ import { ProductVO } from '@/api/iot/product/product'
import ThingModelProperty from './ThingModelProperty.vue'
import ThingModelService from './ThingModelService.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 {
IOT_PROVIDE_KEY,
IoTDataSpecsDataTypeEnum,
@ -93,9 +100,9 @@ const formData = ref<ThingModelData>({
dataSpecs: {
dataType: IoTDataSpecsDataTypeEnum.INT
}
},
service: {},
event: {}
} as IotThingModelProperty,
service: {} as IotThingModelService,
event: {} as IotThingModelEvent
})
const formRef = ref() // Ref
@ -118,20 +125,23 @@ const open = async (type: string, id?: number) => {
dataSpecs: {
dataType: IoTDataSpecsDataTypeEnum.INT
}
}
} as IotThingModelProperty
}
//
if (isEmpty(formData.value.service)) {
formData.value.service = { inputParams: [], outputParams: [] }
formData.value.service = {
inputParams: [],
outputParams: []
} as unknown as IotThingModelService
} else {
formData.value.service.inputParams ??= []
formData.value.service.outputParams ??= []
formData.value.service!.inputParams ??= []
formData.value.service!.outputParams ??= []
}
//
if (isEmpty(formData.value.event)) {
formData.value.event = { outputParams: [] }
formData.value.event = { outputParams: [] } as unknown as IotThingModelEvent
} else {
formData.value.event.outputParams ??= []
formData.value.event!.outputParams ??= []
}
} finally {
formLoading.value = false
@ -217,9 +227,9 @@ const resetForm = () => {
dataSpecs: {
dataType: IoTDataSpecsDataTypeEnum.INT
}
},
service: {},
event: {}
} as IotThingModelProperty,
service: {} as IotThingModelService,
event: {} as IotThingModelEvent
}
formRef.value?.resetFields()
}

View File

@ -22,7 +22,7 @@
IoTDataSpecsDataTypeEnum.INT,
IoTDataSpecsDataTypeEnum.DOUBLE,
IoTDataSpecsDataTypeEnum.FLOAT
].includes(property.dataType || '')
].includes(property.dataType as any)
"
v-model="property.dataSpecs"
/>
@ -60,7 +60,11 @@
label="数据长度"
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>
</el-input>
</el-form-item>
@ -134,7 +138,7 @@ const handleChange = (dataType: any) => {
IoTDataSpecsDataTypeEnum.ENUM,
IoTDataSpecsDataTypeEnum.BOOL,
IoTDataSpecsDataTypeEnum.STRUCT
].includes(dataType) && (property.value.dataSpecs.dataType = dataType)
].includes(dataType) && (property.value.dataSpecs!.dataType = dataType)
switch (dataType) {
case IoTDataSpecsDataTypeEnum.ENUM:
property.value.dataSpecsList.push({

View File

@ -8,14 +8,16 @@
IoTDataSpecsDataTypeEnum.INT,
IoTDataSpecsDataTypeEnum.DOUBLE,
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 v-if="IoTDataSpecsDataTypeEnum.TEXT === data.property.dataType">
数据长度{{ data.property.dataSpecs.length }}
数据长度{{ getDataSpecsValue(data.property, 'length') }}
</div>
<!-- 列表型: 数组结构时间特殊 -->
<div
@ -24,7 +26,7 @@
IoTDataSpecsDataTypeEnum.ARRAY,
IoTDataSpecsDataTypeEnum.STRUCT,
IoTDataSpecsDataTypeEnum.DATE
].includes(data.property.dataType)
].includes(data.property.dataType as any)
"
>
-
@ -32,7 +34,7 @@
<!-- 列表型: 布尔值枚举 -->
<div
v-if="
[IoTDataSpecsDataTypeEnum.BOOL, IoTDataSpecsDataTypeEnum.ENUM].includes(
([IoTDataSpecsDataTypeEnum.BOOL, IoTDataSpecsDataTypeEnum.ENUM] as string[]).includes(
data.property.dataType
)
"
@ -40,7 +42,7 @@
<div>
{{ IoTDataSpecsDataTypeEnum.BOOL === data.property.dataType ? '布尔值' : '枚举值' }}
</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}` }}
</div>
</div>
@ -56,7 +58,7 @@
</template>
<script lang="ts" setup>
import { ThingModelData } from '@/api/iot/thingmodel'
import { ThingModelData, ThingModelProperty } from '@/api/iot/thingmodel'
import {
getEventTypeLabel,
getThingModelServiceCallTypeLabel,
@ -68,6 +70,10 @@ import {
defineOptions({ name: 'DataDefinition' })
defineProps<{ data: ThingModelData }>()
const getDataSpecsValue = (property: ThingModelProperty, key: string) => {
return property.dataSpecs?.[key]
}
</script>
<style lang="scss" scoped></style>