DeviceControlAction.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <div class="bg-[#dbe5f6] flex p-10px">
  3. <div class="flex flex-col items-center justify-center mr-10px h-a">
  4. <el-select
  5. v-model="deviceControlConfig.type"
  6. @change="deviceControlConfig.data = {}"
  7. class="!w-160px"
  8. clearable
  9. placeholder=""
  10. >
  11. <el-option label="属性" :value="IotDeviceMessageTypeEnum.PROPERTY" />
  12. <el-option label="服务" :value="IotDeviceMessageTypeEnum.SERVICE" />
  13. </el-select>
  14. </div>
  15. <div class="">
  16. <div
  17. class="flex items-center justify-around mb-10px last:mb-0"
  18. v-for="(parameter, index) in parameters"
  19. :key="index"
  20. >
  21. <el-select
  22. v-model="parameter.identifier"
  23. class="!w-240px mr-10px"
  24. clearable
  25. placeholder="请选择物模型"
  26. >
  27. <el-option
  28. v-for="thingModel in thingModels"
  29. :key="thingModel.identifier"
  30. :label="thingModel.name"
  31. :value="thingModel.identifier"
  32. />
  33. </el-select>
  34. <el-input v-model="parameter.value" class="!w-240px mr-10px" placeholder="请输入值">
  35. <template v-if="getUnitName(parameter.identifier)" #append>
  36. {{ getUnitName(parameter.identifier) }}
  37. </template>
  38. </el-input>
  39. <el-tooltip content="删除参数" placement="top">
  40. <el-button type="danger" circle size="small" @click="removeParameter(index)">
  41. <Icon icon="ep:delete" />
  42. </el-button>
  43. </el-tooltip>
  44. </div>
  45. </div>
  46. <!-- 添加参数 -->
  47. <div class="flex flex-1 flex-col items-center justify-center w-60px h-a">
  48. <el-tooltip content="添加参数" placement="top">
  49. <el-button type="primary" circle size="small" @click="addParameter">
  50. <Icon icon="ep:plus" />
  51. </el-button>
  52. </el-tooltip>
  53. </div>
  54. </div>
  55. </template>
  56. <script setup lang="ts">
  57. import { useVModel } from '@vueuse/core'
  58. import { ThingModelApi } from '@/api/iot/thingmodel'
  59. import {
  60. ActionDeviceControl,
  61. IotDeviceMessageIdentifierEnum,
  62. IotDeviceMessageTypeEnum
  63. } from '@/api/iot/rule/scene/scene.types'
  64. /** 设备控制执行器组件 */
  65. defineOptions({ name: 'DeviceControlAction' })
  66. const props = defineProps<{
  67. modelValue: any
  68. productId?: number
  69. }>()
  70. const emits = defineEmits(['update:modelValue'])
  71. const deviceControlConfig = useVModel(props, 'modelValue', emits) as Ref<ActionDeviceControl>
  72. const message = useMessage()
  73. /** 执行器参数 */
  74. const parameters = ref<{ identifier: string; value: any }[]>([])
  75. const addParameter = () => {
  76. if (parameters.value.length >= thingModels.value.length) {
  77. message.warning(`该产品只有${thingModels.value.length}个物模型!!!`)
  78. return
  79. }
  80. parameters.value.push({ identifier: '', value: undefined })
  81. }
  82. const removeParameter = (index: number) => {
  83. parameters.value.splice(index, 1)
  84. }
  85. // 初始化设备控制执行器结构
  86. const initDeviceControlConfig = () => {
  87. if (!deviceControlConfig.value) {
  88. deviceControlConfig.value = {
  89. productKey: '',
  90. deviceNames: [],
  91. type: IotDeviceMessageTypeEnum.PROPERTY,
  92. identifier: IotDeviceMessageIdentifierEnum.PROPERTY_SET,
  93. data: {}
  94. } as ActionDeviceControl
  95. }
  96. // 确保data对象存在
  97. if (!deviceControlConfig.value.data) {
  98. deviceControlConfig.value.data = {}
  99. }
  100. }
  101. // 初始化
  102. onMounted(() => {
  103. initDeviceControlConfig()
  104. if (props.productId) {
  105. getThingModelTSL()
  106. }
  107. })
  108. // 监听productId变化
  109. watch(
  110. () => props.productId,
  111. (newVal) => {
  112. if (newVal) {
  113. getThingModelTSL()
  114. // 当产品ID变化时,清空原有数据
  115. deviceControlConfig.value.data = {}
  116. } else {
  117. thingModelTSL.value = undefined
  118. }
  119. }
  120. )
  121. // 监听消息类型变化
  122. watch(
  123. () => deviceControlConfig.value.type,
  124. () => {
  125. // 切换消息类型时清空参数
  126. deviceControlConfig.value.data = {}
  127. if (deviceControlConfig.value.type === IotDeviceMessageTypeEnum.PROPERTY) {
  128. deviceControlConfig.value.identifier = IotDeviceMessageIdentifierEnum.PROPERTY_SET
  129. } else {
  130. deviceControlConfig.value.identifier = ''
  131. }
  132. }
  133. )
  134. // 监听identifier变化
  135. watch(
  136. () => deviceControlConfig.value.identifier,
  137. () => {
  138. // 切换identifier时清空参数
  139. deviceControlConfig.value.data = {}
  140. }
  141. )
  142. /** 获取产品物模型 */
  143. const thingModelTSL = ref<any>()
  144. const getThingModelTSL = async () => {
  145. if (!props.productId) {
  146. return
  147. }
  148. try {
  149. thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(props.productId)
  150. } catch (error) {
  151. console.error('获取物模型失败', error)
  152. }
  153. }
  154. const thingModels = computed((): any[] => {
  155. switch (deviceControlConfig.value.type) {
  156. case IotDeviceMessageTypeEnum.PROPERTY:
  157. return thingModelTSL.value.properties
  158. // TODO puhui999: 服务和事件后续考虑
  159. case IotDeviceMessageTypeEnum.SERVICE:
  160. return thingModelTSL.value.services
  161. case IotDeviceMessageTypeEnum.EVENT:
  162. return thingModelTSL.value.events
  163. }
  164. return []
  165. })
  166. /** 获得属性单位 */
  167. const getUnitName = computed(() => (identifier: string) => {
  168. const model = thingModels.value?.find((item: any) => item.identifier === identifier)
  169. // 属性
  170. if (model?.dataSpecs) {
  171. return model.dataSpecs.unitName
  172. }
  173. // TODO puhui999: 先不考虑服务和事件的情况
  174. // 服务和事件
  175. // if (model?.outputParams) {
  176. // return model.dataSpecs.unitName
  177. // }
  178. return ''
  179. })
  180. </script>