Skip to content

Commit 5d2adca

Browse files
YunaiVgitee-org
authored andcommitted
!628 【功能新增】IOT: ThingModel 服务和事件
Merge pull request !628 from puhui999/feature/iot
2 parents eb5d350 + 9b62862 commit 5d2adca

File tree

12 files changed

+477
-590
lines changed

12 files changed

+477
-590
lines changed

src/api/iot/thingmodel/index.ts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export interface ThingModelData {
1111
productId?: number // 产品编号
1212
productKey?: string // 产品标识
1313
dataType: string // 数据类型,与 dataSpecs 的 dataType 保持一致
14-
type: ProductFunctionTypeEnum // 功能类型
14+
type: number // 功能类型
1515
property: ThingModelProperty // 属性
1616
event?: ThingModelEvent // 事件
1717
service?: ThingModelService // 服务
@@ -38,19 +38,6 @@ export interface ThingModelService {
3838
[key: string]: any
3939
}
4040

41-
// IOT 产品功能(物模型)类型枚举类
42-
export enum ProductFunctionTypeEnum {
43-
PROPERTY = 1, // 属性
44-
SERVICE = 2, // 服务
45-
EVENT = 3 // 事件
46-
}
47-
48-
// IOT 产品功能(物模型)访问模式枚举类
49-
export enum ProductFunctionAccessModeEnum {
50-
READ_WRITE = 'rw', // 读写
51-
READ_ONLY = 'r' // 只读
52-
}
53-
5441
// IoT 产品物模型 API
5542
export const ThingModelApi = {
5643
// 查询产品物模型分页

src/utils/dict.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ export enum DICT_TYPE {
238238
IOT_DEVICE_STATUS = 'iot_device_status', // IOT 设备状态
239239
IOT_PRODUCT_THING_MODEL_TYPE = 'iot_product_thing_model_type', // IOT 产品功能类型
240240
IOT_DATA_TYPE = 'iot_data_type', // IOT 数据类型
241-
IOT_UNIT_TYPE = 'iot_unit_type', // IOT 单位类型
241+
IOT_PRODUCT_THING_MODEL_UNIT = 'iot_product_thing_model_unit', // IOT 物模型单位
242242
IOT_RW_TYPE = 'iot_rw_type', // IOT 读写类型
243243
IOT_PLUGIN_DEPLOY_TYPE = 'iot_plugin_deploy_type', // IOT 插件部署类型
244244
IOT_PLUGIN_STATUS = 'iot_plugin_status', // IOT 插件状态
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<template>
2+
<el-form-item
3+
:rules="[{ required: true, message: '请选择事件类型', trigger: 'change' }]"
4+
label="事件类型"
5+
prop="event.type"
6+
>
7+
<el-radio-group v-model="thingModelEvent.type">
8+
<el-radio :value="ThingModelEventType.INFO.value">
9+
{{ ThingModelEventType.INFO.label }}
10+
</el-radio>
11+
<el-radio :value="ThingModelEventType.ALERT.value">
12+
{{ ThingModelEventType.ALERT.label }}
13+
</el-radio>
14+
<el-radio :value="ThingModelEventType.ERROR.value">
15+
{{ ThingModelEventType.ERROR.label }}
16+
</el-radio>
17+
</el-radio-group>
18+
</el-form-item>
19+
<el-form-item label="输出参数">
20+
<ThingModelInputOutputParam
21+
v-model="thingModelEvent.outputParams"
22+
:direction="ThingModelParamDirection.OUTPUT"
23+
/>
24+
</el-form-item>
25+
</template>
26+
27+
<script lang="ts" setup>
28+
import ThingModelInputOutputParam from './ThingModelInputOutputParam.vue'
29+
import { useVModel } from '@vueuse/core'
30+
import { ThingModelEvent } from '@/api/iot/thingmodel'
31+
import { ThingModelParamDirection, ThingModelEventType } from './config'
32+
33+
/** IoT 物模型事件 */
34+
defineOptions({ name: 'ThingModelEvent' })
35+
36+
const props = defineProps<{ modelValue: any; isStructDataSpecs?: boolean }>()
37+
const emits = defineEmits(['update:modelValue'])
38+
const thingModelEvent = useVModel(props, 'modelValue', emits) as Ref<ThingModelEvent>
39+
</script>
40+
41+
<style lang="scss" scoped>
42+
:deep(.el-form-item) {
43+
.el-form-item {
44+
margin-bottom: 0;
45+
}
46+
}
47+
</style>

src/views/iot/thingmodel/ThingModelForm.vue

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,26 @@
2525
<el-input v-model="formData.identifier" placeholder="请输入标识符" />
2626
</el-form-item>
2727
<!-- 属性配置 -->
28-
<ThingModelDataSpecs
29-
v-if="formData.type === ProductFunctionTypeEnum.PROPERTY"
28+
<ThingModelProperty
29+
v-if="formData.type === ThingModelType.PROPERTY"
3030
v-model="formData.property"
3131
/>
32+
<!-- 服务配置 -->
33+
<ThingModelService
34+
v-if="formData.type === ThingModelType.SERVICE"
35+
v-model="formData.service"
36+
/>
37+
<!-- 事件配置 -->
38+
<ThingModelEvent v-if="formData.type === ThingModelType.EVENT" v-model="formData.event" />
39+
<el-form-item label="描述" prop="description">
40+
<el-input
41+
v-model="formData.description"
42+
:maxlength="200"
43+
:rows="3"
44+
placeholder="请输入属性描述"
45+
type="textarea"
46+
/>
47+
</el-form-item>
3248
</el-form>
3349

3450
<template #footer>
@@ -40,12 +56,15 @@
4056

4157
<script lang="ts" setup>
4258
import { ProductVO } from '@/api/iot/product/product'
43-
import ThingModelDataSpecs from './ThingModelDataSpecs.vue'
44-
import { ProductFunctionTypeEnum, ThingModelApi, ThingModelData } from '@/api/iot/thingmodel'
59+
import ThingModelProperty from './ThingModelProperty.vue'
60+
import ThingModelService from './ThingModelService.vue'
61+
import ThingModelEvent from './ThingModelEvent.vue'
62+
import { ThingModelApi, ThingModelData } from '@/api/iot/thingmodel'
4563
import { IOT_PROVIDE_KEY } from '@/views/iot/utils/constants'
46-
import { DataSpecsDataType, ThingModelFormRules } from './config'
64+
import { DataSpecsDataType, ThingModelFormRules, ThingModelType } from './config'
4765
import { cloneDeep } from 'lodash-es'
4866
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
67+
import { isEmpty } from '@/utils/is'
4968
5069
/** IoT 物模型数据表单 */
5170
defineOptions({ name: 'IoTProductThingModelForm' })
@@ -60,14 +79,16 @@ const dialogTitle = ref('') // 弹窗的标题
6079
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
6180
const formType = ref('') // 表单的类型:create - 新增;update - 修改
6281
const formData = ref<ThingModelData>({
63-
type: ProductFunctionTypeEnum.PROPERTY,
82+
type: ThingModelType.PROPERTY,
6483
dataType: DataSpecsDataType.INT,
6584
property: {
6685
dataType: DataSpecsDataType.INT,
6786
dataSpecs: {
6887
dataType: DataSpecsDataType.INT
6988
}
70-
}
89+
},
90+
service: {},
91+
event: {}
7192
})
7293
7394
const formRef = ref() // 表单 Ref
@@ -92,17 +113,15 @@ defineExpose({ open, close: () => (dialogVisible.value = false) })
92113
/** 提交表单 */
93114
const emit = defineEmits(['success'])
94115
const submitForm = async () => {
116+
debugger
95117
await formRef.value.validate()
96118
formLoading.value = true
97119
try {
98120
const data = cloneDeep(formData.value) as ThingModelData
99121
// 信息补全
100122
data.productId = product!.value.id
101123
data.productKey = product!.value.productKey
102-
data.description = data.property.description
103-
data.dataType = data.property.dataType
104-
data.property.identifier = data.identifier
105-
data.property.name = data.name
124+
fillExtraAttributes(data)
106125
if (formType.value === 'create') {
107126
await ThingModelApi.createThingModel(data)
108127
message.success(t('common.createSuccess'))
@@ -117,17 +136,60 @@ const submitForm = async () => {
117136
}
118137
}
119138
139+
/** 填写额外的属性 */
140+
const fillExtraAttributes = (data: any) => {
141+
// 处理不同类型的情况
142+
// 属性
143+
if (data.type === ThingModelType.PROPERTY) {
144+
removeDataSpecs(data.property)
145+
data.dataType = data.property.dataType
146+
data.property.identifier = data.identifier
147+
data.property.name = data.name
148+
delete data.service
149+
delete data.event
150+
}
151+
// 服务
152+
if (data.type === ThingModelType.SERVICE) {
153+
removeDataSpecs(data.service)
154+
data.dataType = data.service.dataType
155+
data.service.identifier = data.identifier
156+
data.service.name = data.name
157+
delete data.property
158+
delete data.event
159+
}
160+
// 事件
161+
if (data.type === ThingModelType.EVENT) {
162+
removeDataSpecs(data.event)
163+
data.dataType = data.event.dataType
164+
data.event.identifier = data.identifier
165+
data.event.name = data.name
166+
delete data.property
167+
delete data.service
168+
}
169+
}
170+
/** 处理 dataSpecs 为空的情况 */
171+
const removeDataSpecs = (val: any) => {
172+
if (isEmpty(val.dataSpecs)) {
173+
delete val.dataSpecs
174+
}
175+
if (isEmpty(val.dataSpecsList)) {
176+
delete val.dataSpecsList
177+
}
178+
}
179+
120180
/** 重置表单 */
121181
const resetForm = () => {
122182
formData.value = {
123-
type: ProductFunctionTypeEnum.PROPERTY,
183+
type: ThingModelType.PROPERTY,
124184
dataType: DataSpecsDataType.INT,
125185
property: {
126186
dataType: DataSpecsDataType.INT,
127187
dataSpecs: {
128188
dataType: DataSpecsDataType.INT
129189
}
130-
}
190+
},
191+
service: {},
192+
event: {}
131193
}
132194
formRef.value?.resetFields()
133195
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<template>
2+
<div
3+
v-for="(item, index) in thingModelParams"
4+
:key="index"
5+
class="w-1/1 param-item flex justify-between px-10px mb-10px"
6+
>
7+
<span>参数名称:{{ item.name }}</span>
8+
<div class="btn">
9+
<el-button link type="primary" @click="openParamForm(item)">编辑</el-button>
10+
<el-divider direction="vertical" />
11+
<el-button link type="danger" @click="deleteParamItem(index)">删除</el-button>
12+
</div>
13+
</div>
14+
<el-button link type="primary" @click="openParamForm(null)">+新增参数</el-button>
15+
16+
<!-- param 表单 -->
17+
<Dialog v-model="dialogVisible" :title="dialogTitle" append-to-body>
18+
<el-form
19+
ref="paramFormRef"
20+
v-loading="formLoading"
21+
:model="formData"
22+
:rules="ThingModelFormRules"
23+
label-width="100px"
24+
>
25+
<el-form-item label="参数名称" prop="name">
26+
<el-input v-model="formData.name" placeholder="请输入功能名称" />
27+
</el-form-item>
28+
<el-form-item label="标识符" prop="identifier">
29+
<el-input v-model="formData.identifier" placeholder="请输入标识符" />
30+
</el-form-item>
31+
<!-- 属性配置 -->
32+
<ThingModelProperty v-model="formData.property" is-params />
33+
</el-form>
34+
35+
<template #footer>
36+
<el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
37+
<el-button @click="dialogVisible = false">取 消</el-button>
38+
</template>
39+
</Dialog>
40+
</template>
41+
42+
<script lang="ts" setup>
43+
import { useVModel } from '@vueuse/core'
44+
import ThingModelProperty from './ThingModelProperty.vue'
45+
import { DataSpecsDataType, ThingModelFormRules } from './config'
46+
import { isEmpty } from '@/utils/is'
47+
48+
/** 输入输出参数配置组件 */
49+
defineOptions({ name: 'ThingModelInputOutputParam' })
50+
51+
const props = defineProps<{ modelValue: any; direction: string }>()
52+
const emits = defineEmits(['update:modelValue'])
53+
const thingModelParams = useVModel(props, 'modelValue', emits) as Ref<any[]>
54+
const dialogVisible = ref(false) // 弹窗的是否展示
55+
const dialogTitle = ref('新增参数') // 弹窗的标题
56+
const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
57+
const paramFormRef = ref() // 表单 ref
58+
const formData = ref<any>({
59+
dataType: DataSpecsDataType.INT,
60+
property: {
61+
dataType: DataSpecsDataType.INT,
62+
dataSpecs: {
63+
dataType: DataSpecsDataType.INT
64+
}
65+
}
66+
})
67+
68+
/** 打开 param 表单 */
69+
const openParamForm = (val: any) => {
70+
dialogVisible.value = true
71+
resetForm()
72+
if (isEmpty(val)) {
73+
return
74+
}
75+
// 编辑时回显数据
76+
formData.value = {
77+
identifier: val.identifier,
78+
name: val.name,
79+
description: val.description,
80+
property: {
81+
dataType: val.dataType,
82+
dataSpecs: val.dataSpecs,
83+
dataSpecsList: val.dataSpecsList
84+
}
85+
}
86+
}
87+
/** 删除 param 项 */
88+
const deleteParamItem = (index: number) => {
89+
thingModelParams.value.splice(index, 1)
90+
}
91+
92+
/** 添加参数 */
93+
const submitForm = async () => {
94+
// 初始化参数列表
95+
if (isEmpty(thingModelParams.value)) {
96+
thingModelParams.value = []
97+
}
98+
// 校验参数
99+
await paramFormRef.value.validate()
100+
try {
101+
const data = unref(formData)
102+
// 构建数据对象
103+
const item = {
104+
identifier: data.identifier,
105+
name: data.name,
106+
description: data.description,
107+
dataType: data.property.dataType,
108+
paraOrder: 0, // TODO @puhui999: 先写死默认看看后续
109+
direction: props.direction,
110+
dataSpecs:
111+
!!data.property.dataSpecs && Object.keys(data.property.dataSpecs).length > 1
112+
? data.property.dataSpecs
113+
: undefined,
114+
dataSpecsList: isEmpty(data.property.dataSpecsList) ? undefined : data.property.dataSpecsList
115+
}
116+
117+
// 查找是否已有相同 identifier 的项
118+
const existingIndex = thingModelParams.value.findIndex(
119+
(spec) => spec.identifier === data.identifier
120+
)
121+
if (existingIndex > -1) {
122+
// 更新已有项
123+
thingModelParams.value[existingIndex] = item
124+
} else {
125+
// 添加新项
126+
thingModelParams.value.push(item)
127+
}
128+
} finally {
129+
// 隐藏对话框
130+
dialogVisible.value = false
131+
}
132+
}
133+
134+
/** 重置表单 */
135+
const resetForm = () => {
136+
formData.value = {
137+
dataType: DataSpecsDataType.INT,
138+
property: {
139+
dataType: DataSpecsDataType.INT,
140+
dataSpecs: {
141+
dataType: DataSpecsDataType.INT
142+
}
143+
}
144+
}
145+
paramFormRef.value?.resetFields()
146+
}
147+
</script>
148+
149+
<style lang="scss" scoped>
150+
.param-item {
151+
background-color: #e4f2fd;
152+
}
153+
</style>

0 commit comments

Comments
 (0)