Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
admin
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Unverified
Commit
67fb5ecf
authored
Feb 22, 2025
by
芋道源码
Committed by
Gitee
Feb 22, 2025
Browse files
Options
Browse Files
Download
Plain Diff
!705 【代码优化】IoT: 物模型
Merge pull request !705 from puhui999/feature/iot
parents
f7b97d34
0afa0bb1
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
132 additions
and
156 deletions
+132
-156
src/utils/index.ts
+3
-3
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
+9
-73
src/views/iot/thingmodel/ThingModelEvent.vue
+9
-2
src/views/iot/thingmodel/ThingModelProperty.vue
+14
-2
src/views/iot/thingmodel/ThingModelService.vue
+8
-1
src/views/iot/thingmodel/components/DataDefinition.vue
+61
-0
src/views/iot/thingmodel/components/index.ts
+3
-0
src/views/iot/thingmodel/config.ts
+13
-12
src/views/iot/thingmodel/dataSpecs/ThingModelArrayDataSpecs.vue
+2
-2
src/views/iot/thingmodel/dataSpecs/ThingModelStructDataSpecs.vue
+7
-1
src/views/iot/thingmodel/index.vue
+3
-60
No files found.
src/utils/index.ts
View file @
67fb5ecf
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
''
}
}
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
View file @
67fb5ecf
...
...
@@ -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
...
...
src/views/iot/thingmodel/ThingModelEvent.vue
View file @
67fb5ecf
...
...
@@ -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
>
...
...
src/views/iot/thingmodel/ThingModelProperty.vue
View file @
67fb5ecf
...
...
@@ -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
>
...
...
src/views/iot/thingmodel/ThingModelService.vue
View file @
67fb5ecf
...
...
@@ -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
>
...
...
src/views/iot/thingmodel/components/DataDefinition.vue
0 → 100644
View file @
67fb5ecf
<
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
>
src/views/iot/thingmodel/components/index.ts
0 → 100644
View file @
67fb5ecf
import
DataDefinition
from
'./DataDefinition.vue'
export
{
DataDefinition
}
src/views/iot/thingmodel/config.ts
View file @
67fb5ecf
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 产品物模型类型枚举类
...
...
src/views/iot/thingmodel/dataSpecs/ThingModelArrayDataSpecs.vue
View file @
67fb5ecf
...
...
@@ -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
>
...
...
src/views/iot/thingmodel/dataSpecs/ThingModelStructDataSpecs.vue
View file @
67fb5ecf
...
...
@@ -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
>
...
...
src/views/iot/thingmodel/index.vue
View file @
67fb5ecf
...
...
@@ -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'
})
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment