!705 【代码优化】IoT: 物模型

Merge pull request !705 from puhui999/feature/iot
This commit is contained in:
芋道源码 2025-02-22 09:58:38 +00:00 committed by Gitee
commit 67fb5ecf3a
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 132 additions and 156 deletions

View File

@ -1,4 +1,4 @@
import { toNumber } from 'lodash-es'
import {toNumber} from 'lodash-es'
/**
*
@ -118,7 +118,7 @@ export function toAnyString() {
/**
*
*
*
* @param length
*/
export function generateRandomStr(length: number): string {
@ -459,7 +459,7 @@ export function jsonParse(str: string) {
try {
return JSON.parse(str)
} catch (e) {
console.error(`str[${str}] 不是一个 JSON 字符串`)
// console.error(`str[${str}] 不是一个 JSON 字符串`)
return ''
}
}

View File

@ -7,7 +7,7 @@
<el-tabs v-model="activeTab" type="border-card">
<!-- 上行指令调试 -->
<el-tab-pane label="上行指令调试" name="up">
<el-tabs v-model="subTab" v-if="activeTab === 'up'">
<el-tabs v-if="activeTab === 'up'" v-model="subTab">
<!-- 属性上报 -->
<el-tab-pane label="属性上报" name="property">
<ContentWrap>
@ -29,70 +29,11 @@
</el-table-column>
<el-table-column align="left" label="数据定义" prop="identifier">
<template #default="{ row }">
<!-- 属性 -->
<template v-if="row.type === ThingModelType.PROPERTY">
<!-- 非列表型数值 -->
<div
v-if="
[
DataSpecsDataType.INT,
DataSpecsDataType.DOUBLE,
DataSpecsDataType.FLOAT
].includes(row.property.dataType)
"
>
取值范围
{{ `${row.property.dataSpecs.min}~${row.property.dataSpecs.max}` }}
</div>
<!-- 非列表型文本 -->
<div v-if="DataSpecsDataType.TEXT === row.property.dataType">
数据长度{{ row.property.dataSpecs.length }}
</div>
<!-- 列表型: 数组结构时间特殊 -->
<div
v-if="
[
DataSpecsDataType.ARRAY,
DataSpecsDataType.STRUCT,
DataSpecsDataType.DATE
].includes(row.property.dataType)
"
>
-
</div>
<!-- 列表型: 布尔值枚举 -->
<div
v-if="
[DataSpecsDataType.BOOL, DataSpecsDataType.ENUM].includes(
row.property.dataType
)
"
>
<div>
{{
DataSpecsDataType.BOOL === row.property.dataType
? '布尔值'
: '枚举值'
}}
</div>
<div v-for="item in row.property.dataSpecsList" :key="item.value">
{{ `${item.name}-${item.value}` }}
</div>
</div>
<!-- TODO @super要不要兜底下没翻译的类型直接展示 json -->
</template>
<!-- 服务 -->
<div v-if="row.type === ThingModelType.SERVICE">
调用方式{{ getCallTypeByValue(row.service.callType) }}
</div>
<!-- 事件 -->
<div v-if="row.type === ThingModelType.EVENT">
事件类型{{ getEventTypeByValue(row.event.type) }}
</div>
<DataDefinition :data="row" />
</template>
</el-table-column>
<!-- TODO @super可以右侧 fixed -->
<el-table-column label="值" align="center" width="80">
<el-table-column align="center" label="值" width="80">
<template #default="scope">
<el-input v-model="scope.row.simulateValue" class="!w-60px" />
</template>
@ -100,7 +41,7 @@
</el-table>
<!-- TODO @super发送按钮可以放在右侧哈因为我们的 simulateValue 就在最右侧 -->
<div class="mt-10px">
<el-button type="primary" @click="handlePropertyReport"> 发送 </el-button>
<el-button type="primary" @click="handlePropertyReport"> 发送</el-button>
</div>
</ContentWrap>
</el-tab-pane>
@ -151,7 +92,7 @@
<!-- 下行指令调试 -->
<!-- TODO @super待实现 -->
<el-tab-pane label="下行指令调试" name="down">
<el-tabs v-model="subTab" v-if="activeTab === 'down'">
<el-tabs v-if="activeTab === 'down'" v-model="subTab">
<!-- 属性调试 -->
<el-tab-pane label="属性调试" name="propertyDebug">
<ContentWrap>
@ -201,18 +142,13 @@
</ContentWrap>
</template>
<script setup lang="ts">
<script lang="ts" setup>
import { ProductVO } from '@/api/iot/product/product'
import { ThingModelApi, SimulatorData } from '@/api/iot/thingmodel'
import { SimulatorData, ThingModelApi } from '@/api/iot/thingmodel'
import { DeviceApi, DeviceStateEnum, DeviceVO } from '@/api/iot/device/device'
import DeviceDetailsLog from './DeviceDetailsLog.vue'
import {
DataSpecsDataType,
getCallTypeByValue,
getDataTypeOptionsLabel,
getEventTypeByValue,
ThingModelType
} from '@/views/iot/thingmodel/config'
import { getDataTypeOptionsLabel } from '@/views/iot/thingmodel/config'
import { DataDefinition } from '@/views/iot/thingmodel/components'
const props = defineProps<{
product: ProductVO

View File

@ -5,7 +5,6 @@
label="事件类型"
prop="event.type"
>
<!-- TODO @puhui999默认选中INFO 信息 -->
<el-radio-group v-model="thingModelEvent.type">
<el-radio :value="ThingModelEventType.INFO.value">
{{ ThingModelEventType.INFO.label }}
@ -30,7 +29,8 @@
import ThingModelInputOutputParam from './ThingModelInputOutputParam.vue'
import { useVModel } from '@vueuse/core'
import { ThingModelEvent } from '@/api/iot/thingmodel'
import { ThingModelParamDirection, ThingModelEventType } from './config'
import { ThingModelEventType, ThingModelParamDirection } from './config'
import { isEmpty } from '@/utils/is'
/** IoT 物模型事件 */
defineOptions({ name: 'ThingModelEvent' })
@ -38,6 +38,13 @@ defineOptions({ name: 'ThingModelEvent' })
const props = defineProps<{ modelValue: any; isStructDataSpecs?: boolean }>()
const emits = defineEmits(['update:modelValue'])
const thingModelEvent = useVModel(props, 'modelValue', emits) as Ref<ThingModelEvent>
// INFO
watch(
() => thingModelEvent.value.type,
(val: string) => isEmpty(val) && (thingModelEvent.value.type = ThingModelEventType.INFO.value),
{ immediate: true }
)
</script>
<style lang="scss" scoped>

View File

@ -10,7 +10,7 @@
<el-option
v-for="option in getDataTypeOptions"
:key="option.value"
:label="option.label"
:label="`${option.value}(${option.label})`"
:value="option.value"
/>
</el-select>
@ -76,7 +76,6 @@
v-if="property.dataType === DataSpecsDataType.STRUCT"
v-model="property.dataSpecsList"
/>
<!-- TODO @puhui999默认选中第一个 -->
<el-form-item v-if="!isStructDataSpecs && !isParams" label="读写类型" prop="property.accessMode">
<el-radio-group v-model="property.accessMode">
<el-radio :label="ThingModelAccessMode.READ_WRITE.value">
@ -104,6 +103,7 @@ import {
ThingModelStructDataSpecs
} from './dataSpecs'
import { ThingModelProperty } from '@/api/iot/thingmodel'
import { isEmpty } from '@/utils/is'
/** IoT 物模型属性 */
defineOptions({ name: 'ThingModelProperty' })
@ -146,6 +146,18 @@ const handleChange = (dataType: any) => {
break
}
}
//
watch(
() => property.value.accessMode,
(val: string) => {
if (props.isStructDataSpecs || props.isParams) {
return
}
isEmpty(val) && (property.value.accessMode = ThingModelAccessMode.READ_WRITE.value)
},
{ immediate: true }
)
</script>
<style lang="scss" scoped>

View File

@ -5,7 +5,6 @@
label="调用方式"
prop="service.callType"
>
<!-- TODO @puhui999默认选中ASYNC 异步 -->
<el-radio-group v-model="service.callType">
<el-radio :value="ThingModelServiceCallType.ASYNC.value">
{{ ThingModelServiceCallType.ASYNC.label }}
@ -34,6 +33,7 @@ import ThingModelInputOutputParam from './ThingModelInputOutputParam.vue'
import { useVModel } from '@vueuse/core'
import { ThingModelService } from '@/api/iot/thingmodel'
import { ThingModelParamDirection, ThingModelServiceCallType } from './config'
import { isEmpty } from '@/utils/is'
/** IoT 物模型服务 */
defineOptions({ name: 'ThingModelService' })
@ -41,6 +41,13 @@ defineOptions({ name: 'ThingModelService' })
const props = defineProps<{ modelValue: any; isStructDataSpecs?: boolean }>()
const emits = defineEmits(['update:modelValue'])
const service = useVModel(props, 'modelValue', emits) as Ref<ThingModelService>
// ASYNC
watch(
() => service.value.callType,
(val: string) => isEmpty(val) && (service.value.callType = ThingModelServiceCallType.ASYNC.value),
{ immediate: true }
)
</script>
<style lang="scss" scoped>

View File

@ -0,0 +1,61 @@
<template>
<!-- 属性 -->
<template v-if="data.type === ThingModelType.PROPERTY">
<!-- 非列表型数值 -->
<div
v-if="
[DataSpecsDataType.INT, DataSpecsDataType.DOUBLE, DataSpecsDataType.FLOAT].includes(
data.property.dataType
)
"
>
取值范围{{ `${data.property.dataSpecs.min}~${data.property.dataSpecs.max}` }}
</div>
<!-- 非列表型文本 -->
<div v-if="DataSpecsDataType.TEXT === data.property.dataType">
数据长度{{ data.property.dataSpecs.length }}
</div>
<!-- 列表型: 数组结构时间特殊 -->
<div
v-if="
[DataSpecsDataType.ARRAY, DataSpecsDataType.STRUCT, DataSpecsDataType.DATE].includes(
data.property.dataType
)
"
>
-
</div>
<!-- 列表型: 布尔值枚举 -->
<div v-if="[DataSpecsDataType.BOOL, DataSpecsDataType.ENUM].includes(data.property.dataType)">
<div> {{ DataSpecsDataType.BOOL === data.property.dataType ? '布尔值' : '枚举值' }}</div>
<div v-for="item in data.property.dataSpecsList" :key="item.value">
{{ `${item.name}-${item.value}` }}
</div>
</div>
</template>
<!-- 服务 -->
<div v-if="data.type === ThingModelType.SERVICE">
调用方式{{ getCallTypeByValue(data.service!.callType) }}
</div>
<!-- 事件 -->
<div v-if="data.type === ThingModelType.EVENT">
事件类型{{ getEventTypeByValue(data.event!.type) }}
</div>
</template>
<script lang="ts" setup>
import {
DataSpecsDataType,
getCallTypeByValue,
getEventTypeByValue,
ThingModelType
} from '@/views/iot/thingmodel/config'
import { ThingModelData } from '@/api/iot/thingmodel'
/** 数据定义展示组件 */
defineOptions({ name: 'DataDefinition' })
defineProps<{ data: ThingModelData }>()
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,3 @@
import DataDefinition from './DataDefinition.vue'
export { DataDefinition }

View File

@ -1,4 +1,4 @@
import { isEmpty } from '@/utils/is'
import {isEmpty} from '@/utils/is'
/** dataSpecs 数值型数据结构 */
export interface DataSpecsNumberDataVO {
@ -21,7 +21,7 @@ export interface DataSpecsEnumOrBoolDataVO {
}
/** 属性值的数据类型 */
// TODO @puhui999这个枚举类要不放到 dict 里?
// TODO @puhui999这个枚举类要不放到 dict 里? 这个全是当常量来使用的不好放 dict 里 🤣
export const DataSpecsDataType = {
INT: 'int',
FLOAT: 'float',
@ -37,15 +37,15 @@ export const DataSpecsDataType = {
/** 物体模型数据类型配置项 */
// TODO @puhui999搞到字典里label 只使用()部分,就是整数型、单精度浮点型等,这种哈。这样,拼接 value(label) 就可以渲染出来,通用性更强
export const dataTypeOptions = [
{ value: DataSpecsDataType.INT, label: 'int32 (整数型)' },
{ value: DataSpecsDataType.FLOAT, label: 'float (单精度浮点型)' },
{ value: DataSpecsDataType.DOUBLE, label: 'double (双精度浮点型)' },
{ value: DataSpecsDataType.ENUM, label: 'enum(枚举型)' },
{ value: DataSpecsDataType.BOOL, label: 'bool (布尔型)' },
{ value: DataSpecsDataType.TEXT, label: 'text (文本型)' },
{ value: DataSpecsDataType.DATE, label: 'date (时间型)' },
{ value: DataSpecsDataType.STRUCT, label: 'struct (结构体)' },
{ value: DataSpecsDataType.ARRAY, label: 'array (数组)' }
{ value: DataSpecsDataType.INT, label: '整数型' },
{ value: DataSpecsDataType.FLOAT, label: '单精度浮点型' },
{ value: DataSpecsDataType.DOUBLE, label: '双精度浮点型' },
{ value: DataSpecsDataType.ENUM, label: '枚举型' },
{ value: DataSpecsDataType.BOOL, label: '布尔型' },
{ value: DataSpecsDataType.TEXT, label: '文本型' },
{ value: DataSpecsDataType.DATE, label: '时间型' },
{ value: DataSpecsDataType.STRUCT, label: '结构体' },
{ value: DataSpecsDataType.ARRAY, label: '数组' }
]
/** 获得物体模型数据类型配置项名称 */
@ -53,7 +53,8 @@ export const getDataTypeOptionsLabel = (value: string) => {
if (isEmpty(value)) {
return value
}
return dataTypeOptions.find((option) => option.value === value)?.label
const dataType = dataTypeOptions.find((option) => option.value === value)
return dataType && `${dataType.value}(${dataType.label})`
}
// IOT 产品物模型类型枚举类

View File

@ -4,15 +4,15 @@
<el-radio-group v-model="dataSpecs.childDataType" @change="handleChange">
<template v-for="item in dataTypeOptions" :key="item.value">
<el-radio
class="w-1/3"
v-if="
!(
[DataSpecsDataType.ENUM, DataSpecsDataType.ARRAY, DataSpecsDataType.DATE] as any[]
).includes(item.value)
"
:value="item.value"
class="w-1/3"
>
{{ item.label }}
{{ `${item.value}(${item.label})` }}
</el-radio>
</template>
</el-radio-group>

View File

@ -5,7 +5,6 @@
:rules="[{ required: true, validator: validateList, trigger: 'change' }]"
label="JSON 对象"
>
<!-- TODO @puhui999编辑已经添加的结构体里面的参数加不上 -->
<div
v-for="(item, index) in dataSpecsList"
:key="index"
@ -155,6 +154,13 @@ const validateList = (_: any, __: any, callback: any) => {
}
callback()
}
/** 组件初始化 */
onMounted(async () => {
await nextTick()
// dataSpecsList
isEmpty(dataSpecsList.value) && (dataSpecsList.value = [])
})
</script>
<style lang="scss" scoped>

View File

@ -64,59 +64,7 @@
</el-table-column>
<el-table-column align="left" label="数据定义" prop="identifier">
<template #default="{ row }">
<!-- 属性 -->
<template v-if="row.type === ThingModelType.PROPERTY">
<!-- 非列表型数值 -->
<div
v-if="
[
DataSpecsDataType.INT,
DataSpecsDataType.DOUBLE,
DataSpecsDataType.FLOAT
].includes(row.property.dataType)
"
>
<!-- TODO @puhui999把数据定义抽成一个方法这样其它地方也可以复用哈 -->
取值范围{{ `${row.property.dataSpecs.min}~${row.property.dataSpecs.max}` }}
</div>
<!-- 非列表型文本 -->
<div v-if="DataSpecsDataType.TEXT === row.property.dataType">
数据长度{{ row.property.dataSpecs.length }}
</div>
<!-- 列表型: 数组结构时间特殊 -->
<div
v-if="
[
DataSpecsDataType.ARRAY,
DataSpecsDataType.STRUCT,
DataSpecsDataType.DATE
].includes(row.property.dataType)
"
>
-
</div>
<!-- 列表型: 布尔值枚举 -->
<div
v-if="
[DataSpecsDataType.BOOL, DataSpecsDataType.ENUM].includes(row.property.dataType)
"
>
<div>
{{ DataSpecsDataType.BOOL === row.property.dataType ? '布尔值' : '枚举值' }}
</div>
<div v-for="item in row.property.dataSpecsList" :key="item.value">
{{ `${item.name}-${item.value}` }}
</div>
</div>
</template>
<!-- 服务 -->
<div v-if="row.type === ThingModelType.SERVICE">
调用方式{{ getCallTypeByValue(row.service.callType) }}
</div>
<!-- 事件 -->
<div v-if="row.type === ThingModelType.EVENT">
事件类型{{ getEventTypeByValue(row.event.type) }}
</div>
<DataDefinition :data="row" />
</template>
</el-table-column>
<el-table-column align="center" label="操作">
@ -158,13 +106,8 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import ThingModelForm from './ThingModelForm.vue'
import { ProductVO } from '@/api/iot/product/product'
import { IOT_PROVIDE_KEY } from '@/views/iot/utils/constants'
import {
DataSpecsDataType,
getCallTypeByValue,
getDataTypeOptionsLabel,
getEventTypeByValue,
ThingModelType
} from './config'
import { getDataTypeOptionsLabel } from './config'
import { DataDefinition } from './components'
defineOptions({ name: 'IoTThingModel' })