Quellcode durchsuchen

!705 【代码优化】IoT: 物模型
Merge pull request !705 from puhui999/feature/iot

芋道源码 vor 5 Monaten
Ursprung
Commit
67fb5ecf3a

+ 3 - 3
src/utils/index.ts

@@ -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 ''
   }
 }

+ 9 - 73
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue

@@ -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

+ 9 - 2
src/views/iot/thingmodel/ThingModelEvent.vue

@@ -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>

+ 14 - 2
src/views/iot/thingmodel/ThingModelProperty.vue

@@ -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>

+ 8 - 1
src/views/iot/thingmodel/ThingModelService.vue

@@ -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>

+ 61 - 0
src/views/iot/thingmodel/components/DataDefinition.vue

@@ -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>

+ 3 - 0
src/views/iot/thingmodel/components/index.ts

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

+ 13 - 12
src/views/iot/thingmodel/config.ts

@@ -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 产品物模型类型枚举类

+ 2 - 2
src/views/iot/thingmodel/dataSpecs/ThingModelArrayDataSpecs.vue

@@ -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>

+ 7 - 1
src/views/iot/thingmodel/dataSpecs/ThingModelStructDataSpecs.vue

@@ -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>

+ 3 - 60
src/views/iot/thingmodel/index.vue

@@ -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' })