ThingModelProperty.vue 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <!-- 产品的物模型表单(property 项) -->
  2. <template>
  3. <el-form-item
  4. :rules="[{ required: true, message: '请选择数据类型', trigger: 'change' }]"
  5. label="数据类型"
  6. prop="property.dataType"
  7. >
  8. <el-select v-model="property.dataType" placeholder="请选择数据类型" @change="handleChange">
  9. <!-- ARRAY 和 STRUCT 类型数据相互嵌套时,最多支持递归嵌套 2 层(父和子) -->
  10. <el-option
  11. v-for="option in getDataTypeOptions2"
  12. :key="option.value"
  13. :label="`${option.value}(${option.label})`"
  14. :value="option.value"
  15. />
  16. </el-select>
  17. </el-form-item>
  18. <!-- 数值型配置 -->
  19. <ThingModelNumberDataSpecs
  20. v-if="
  21. [
  22. IoTDataSpecsDataTypeEnum.INT,
  23. IoTDataSpecsDataTypeEnum.DOUBLE,
  24. IoTDataSpecsDataTypeEnum.FLOAT
  25. ].includes(property.dataType || '')
  26. "
  27. v-model="property.dataSpecs"
  28. />
  29. <!-- 枚举型配置 -->
  30. <ThingModelEnumDataSpecs
  31. v-if="property.dataType === IoTDataSpecsDataTypeEnum.ENUM"
  32. v-model="property.dataSpecsList"
  33. />
  34. <!-- 布尔型配置 -->
  35. <el-form-item v-if="property.dataType === IoTDataSpecsDataTypeEnum.BOOL" label="布尔值">
  36. <template v-for="(item, index) in property.dataSpecsList" :key="item.value">
  37. <div class="flex items-center justify-start w-1/1 mb-5px">
  38. <span>{{ item.value }}</span>
  39. <span class="mx-2">-</span>
  40. <el-form-item
  41. :prop="`property.dataSpecsList[${index}].name`"
  42. :rules="[
  43. { required: true, message: '枚举描述不能为空' },
  44. { validator: validateBoolName, trigger: 'blur' }
  45. ]"
  46. class="flex-1 mb-0"
  47. >
  48. <el-input
  49. v-model="item.name"
  50. :placeholder="`如:${item.value === 0 ? '关' : '开'}`"
  51. class="w-255px!"
  52. />
  53. </el-form-item>
  54. </div>
  55. </template>
  56. </el-form-item>
  57. <!-- 文本型配置 -->
  58. <el-form-item
  59. v-if="property.dataType === IoTDataSpecsDataTypeEnum.TEXT"
  60. label="数据长度"
  61. prop="property.dataSpecs.length"
  62. >
  63. <el-input v-model="property.dataSpecs.length" class="w-255px!" placeholder="请输入文本字节长度">
  64. <template #append>字节</template>
  65. </el-input>
  66. </el-form-item>
  67. <!-- 时间型配置 -->
  68. <el-form-item
  69. v-if="property.dataType === IoTDataSpecsDataTypeEnum.DATE"
  70. label="时间格式"
  71. prop="date"
  72. >
  73. <el-input class="w-255px!" disabled placeholder="String 类型的 UTC 时间戳(毫秒)" />
  74. </el-form-item>
  75. <!-- 数组型配置-->
  76. <ThingModelArrayDataSpecs
  77. v-if="property.dataType === IoTDataSpecsDataTypeEnum.ARRAY"
  78. v-model="property.dataSpecs"
  79. />
  80. <!-- Struct 型配置-->
  81. <ThingModelStructDataSpecs
  82. v-if="property.dataType === IoTDataSpecsDataTypeEnum.STRUCT"
  83. v-model="property.dataSpecsList"
  84. />
  85. <el-form-item v-if="!isStructDataSpecs && !isParams" label="读写类型" prop="property.accessMode">
  86. <el-radio-group v-model="property.accessMode">
  87. <el-radio
  88. v-for="accessMode in Object.values(IoTThingModelAccessModeEnum)"
  89. :key="accessMode.value"
  90. :label="accessMode.value"
  91. >
  92. {{ accessMode.label }}
  93. </el-radio>
  94. </el-radio-group>
  95. </el-form-item>
  96. </template>
  97. <script lang="ts" setup>
  98. import { useVModel } from '@vueuse/core'
  99. import {
  100. ThingModelArrayDataSpecs,
  101. ThingModelEnumDataSpecs,
  102. ThingModelNumberDataSpecs,
  103. ThingModelStructDataSpecs
  104. } from './dataSpecs'
  105. import { ThingModelProperty, validateBoolName } from '@/api/iot/thingmodel'
  106. import { isEmpty } from '@/utils/is'
  107. import {
  108. getDataTypeOptions,
  109. IoTDataSpecsDataTypeEnum,
  110. IoTThingModelAccessModeEnum
  111. } from '@/views/iot/utils/constants'
  112. /** IoT 物模型属性 */
  113. defineOptions({ name: 'ThingModelProperty' })
  114. const props = defineProps<{ modelValue: any; isStructDataSpecs?: boolean; isParams?: boolean }>()
  115. const emits = defineEmits(['update:modelValue'])
  116. const property = useVModel(props, 'modelValue', emits) as Ref<ThingModelProperty>
  117. const getDataTypeOptions2 = computed(() => {
  118. if (!props.isStructDataSpecs) {
  119. return getDataTypeOptions()
  120. }
  121. const excludedTypes = [IoTDataSpecsDataTypeEnum.STRUCT, IoTDataSpecsDataTypeEnum.ARRAY]
  122. return getDataTypeOptions().filter((item: any) => !excludedTypes.includes(item.value))
  123. }) // 获得数据类型列表
  124. /** 属性值的数据类型切换时初始化相关数据 */
  125. const handleChange = (dataType: any) => {
  126. property.value.dataSpecs = {}
  127. property.value.dataSpecsList = []
  128. // 不是列表型数据才设置 dataSpecs.dataType
  129. ![
  130. IoTDataSpecsDataTypeEnum.ENUM,
  131. IoTDataSpecsDataTypeEnum.BOOL,
  132. IoTDataSpecsDataTypeEnum.STRUCT
  133. ].includes(dataType) && (property.value.dataSpecs.dataType = dataType)
  134. switch (dataType) {
  135. case IoTDataSpecsDataTypeEnum.ENUM:
  136. property.value.dataSpecsList.push({
  137. dataType: IoTDataSpecsDataTypeEnum.ENUM,
  138. name: '', // 枚举项的名称
  139. value: undefined // 枚举值
  140. })
  141. break
  142. case IoTDataSpecsDataTypeEnum.BOOL:
  143. for (let i = 0; i < 2; i++) {
  144. property.value.dataSpecsList.push({
  145. dataType: IoTDataSpecsDataTypeEnum.BOOL,
  146. name: '', // 布尔值的名称
  147. value: i // 布尔值
  148. })
  149. }
  150. break
  151. }
  152. }
  153. /** 默认选中读写 */
  154. watch(
  155. () => property.value.accessMode,
  156. (val: string) => {
  157. if (props.isStructDataSpecs || props.isParams) {
  158. return
  159. }
  160. isEmpty(val) && (property.value.accessMode = IoTThingModelAccessModeEnum.READ_WRITE.value)
  161. },
  162. { immediate: true }
  163. )
  164. </script>
  165. <style lang="scss" scoped>
  166. :deep(.el-form-item) {
  167. .el-form-item {
  168. margin-bottom: 0;
  169. }
  170. }
  171. </style>