|
@@ -1,78 +1,61 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <div class="bg-[#dbe5f6] p-10px">
|
|
|
|
|
- <div class="flex items-center mb-10px">
|
|
|
|
|
- <span class="mr-10px w-60px">产品</span>
|
|
|
|
|
- <el-button type="primary" @click="productTableSelectRef?.open()" size="small" plain>
|
|
|
|
|
- {{ product ? product.name : '选择产品' }}
|
|
|
|
|
- </el-button>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex items-center mb-10px">
|
|
|
|
|
- <span class="mr-10px w-60px">设备</span>
|
|
|
|
|
- <el-button type="primary" @click="openDeviceSelect" size="small" plain>
|
|
|
|
|
- {{ isEmpty(deviceList) ? '选择设备' : deviceControlConfig.deviceNames.join(',') }}
|
|
|
|
|
- </el-button>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="flex items-center mb-10px">
|
|
|
|
|
- <span class="mr-10px w-60px">消息类型</span>
|
|
|
|
|
|
|
+ <div class="bg-[#dbe5f6] flex p-10px">
|
|
|
|
|
+ <div class="flex flex-col items-center justify-center mr-10px h-a">
|
|
|
<el-select
|
|
<el-select
|
|
|
v-model="deviceControlConfig.type"
|
|
v-model="deviceControlConfig.type"
|
|
|
|
|
+ @change="deviceControlConfig.data = {}"
|
|
|
class="!w-160px"
|
|
class="!w-160px"
|
|
|
clearable
|
|
clearable
|
|
|
- placeholder="选择消息类型"
|
|
|
|
|
|
|
+ placeholder=""
|
|
|
>
|
|
>
|
|
|
<el-option label="属性" :value="IotDeviceMessageTypeEnum.PROPERTY" />
|
|
<el-option label="属性" :value="IotDeviceMessageTypeEnum.PROPERTY" />
|
|
|
<el-option label="服务" :value="IotDeviceMessageTypeEnum.SERVICE" />
|
|
<el-option label="服务" :value="IotDeviceMessageTypeEnum.SERVICE" />
|
|
|
</el-select>
|
|
</el-select>
|
|
|
</div>
|
|
</div>
|
|
|
- <div v-if="deviceControlConfig.type" class="flex items-center mb-10px">
|
|
|
|
|
- <span class="mr-10px w-60px">具体操作</span>
|
|
|
|
|
- <el-select
|
|
|
|
|
- v-model="deviceControlConfig.identifier"
|
|
|
|
|
- class="!w-240px"
|
|
|
|
|
- clearable
|
|
|
|
|
- placeholder="选择操作项"
|
|
|
|
|
|
|
+ <div class="">
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="flex items-center justify-around mb-10px last:mb-0"
|
|
|
|
|
+ v-for="(parameter, index) in parameters"
|
|
|
|
|
+ :key="index"
|
|
|
>
|
|
>
|
|
|
- <template v-if="deviceControlConfig.type === IotDeviceMessageTypeEnum.PROPERTY">
|
|
|
|
|
- <el-option :value="IotDeviceMessageIdentifierEnum.PROPERTY_SET" label="属性设置" />
|
|
|
|
|
- </template>
|
|
|
|
|
- <template v-else-if="deviceControlConfig.type === IotDeviceMessageTypeEnum.SERVICE">
|
|
|
|
|
|
|
+ <el-select
|
|
|
|
|
+ v-model="parameter.identifier"
|
|
|
|
|
+ class="!w-240px mr-10px"
|
|
|
|
|
+ clearable
|
|
|
|
|
+ placeholder="请选择物模型"
|
|
|
|
|
+ >
|
|
|
<el-option
|
|
<el-option
|
|
|
- v-for="model in thingModelTSL?.services"
|
|
|
|
|
- :key="model.identifier"
|
|
|
|
|
- :label="model.name"
|
|
|
|
|
- :value="model.identifier"
|
|
|
|
|
|
|
+ v-for="thingModel in thingModels"
|
|
|
|
|
+ :key="thingModel.identifier"
|
|
|
|
|
+ :label="thingModel.name"
|
|
|
|
|
+ :value="thingModel.identifier"
|
|
|
/>
|
|
/>
|
|
|
- </template>
|
|
|
|
|
- </el-select>
|
|
|
|
|
|
|
+ </el-select>
|
|
|
|
|
+ <el-input v-model="parameter.value" class="!w-240px mr-10px" placeholder="请输入值">
|
|
|
|
|
+ <template v-if="getUnitName(parameter.identifier)" #append>
|
|
|
|
|
+ {{ getUnitName(parameter.identifier) }}
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-input>
|
|
|
|
|
+ <el-tooltip content="删除参数" placement="top">
|
|
|
|
|
+ <el-button type="danger" circle size="small" @click="removeParameter(index)">
|
|
|
|
|
+ <Icon icon="ep:delete" />
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-tooltip>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 添加参数 -->
|
|
|
|
|
+ <div class="flex flex-1 flex-col items-center justify-center w-60px h-a">
|
|
|
|
|
+ <el-tooltip content="添加参数" placement="top">
|
|
|
|
|
+ <el-button type="primary" circle size="small" @click="addParameter">
|
|
|
|
|
+ <Icon icon="ep:plus" />
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ </el-tooltip>
|
|
|
</div>
|
|
</div>
|
|
|
- <DeviceActionControl
|
|
|
|
|
- v-if="deviceControlConfig.identifier && deviceControlConfig.type"
|
|
|
|
|
- :model-value="deviceControlConfig.data"
|
|
|
|
|
- :thing-models="getThingModels()"
|
|
|
|
|
- :message-type="deviceControlConfig.type"
|
|
|
|
|
- :identifier="deviceControlConfig.identifier"
|
|
|
|
|
- @update:model-value="(val) => (deviceControlConfig.data = val)"
|
|
|
|
|
- />
|
|
|
|
|
</div>
|
|
</div>
|
|
|
-
|
|
|
|
|
- <!-- 产品、设备的选择 -->
|
|
|
|
|
- <ProductTableSelect ref="productTableSelectRef" @success="handleProductSelect" />
|
|
|
|
|
- <DeviceTableSelect
|
|
|
|
|
- ref="deviceTableSelectRef"
|
|
|
|
|
- multiple
|
|
|
|
|
- :product-id="product?.id"
|
|
|
|
|
- @success="handleDeviceSelect"
|
|
|
|
|
- />
|
|
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { useVModel } from '@vueuse/core'
|
|
import { useVModel } from '@vueuse/core'
|
|
|
-import { isEmpty } from '@/utils/is'
|
|
|
|
|
-import ProductTableSelect from '@/views/iot/product/product/components/ProductTableSelect.vue'
|
|
|
|
|
-import DeviceTableSelect from '@/views/iot/device/device/components/DeviceTableSelect.vue'
|
|
|
|
|
-import DeviceActionControl from './DeviceActionControl.vue'
|
|
|
|
|
-import { ProductVO } from '@/api/iot/product/product'
|
|
|
|
|
-import { DeviceVO } from '@/api/iot/device/device'
|
|
|
|
|
import { ThingModelApi } from '@/api/iot/thingmodel'
|
|
import { ThingModelApi } from '@/api/iot/thingmodel'
|
|
|
import {
|
|
import {
|
|
|
ActionDeviceControl,
|
|
ActionDeviceControl,
|
|
@@ -83,12 +66,27 @@ import {
|
|
|
/** 设备控制执行器组件 */
|
|
/** 设备控制执行器组件 */
|
|
|
defineOptions({ name: 'DeviceControlAction' })
|
|
defineOptions({ name: 'DeviceControlAction' })
|
|
|
|
|
|
|
|
-const props = defineProps<{ modelValue: any }>()
|
|
|
|
|
|
|
+const props = defineProps<{
|
|
|
|
|
+ modelValue: any
|
|
|
|
|
+ productId?: number
|
|
|
|
|
+}>()
|
|
|
const emits = defineEmits(['update:modelValue'])
|
|
const emits = defineEmits(['update:modelValue'])
|
|
|
const deviceControlConfig = useVModel(props, 'modelValue', emits) as Ref<ActionDeviceControl>
|
|
const deviceControlConfig = useVModel(props, 'modelValue', emits) as Ref<ActionDeviceControl>
|
|
|
|
|
|
|
|
const message = useMessage()
|
|
const message = useMessage()
|
|
|
|
|
|
|
|
|
|
+/** 执行器参数 */
|
|
|
|
|
+const parameters = ref<{ identifier: string; value: any }[]>([])
|
|
|
|
|
+const addParameter = () => {
|
|
|
|
|
+ if (parameters.value.length >= thingModels.value.length) {
|
|
|
|
|
+ message.warning(`该产品只有${thingModels.value.length}个物模型!!!`)
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ parameters.value.push({ identifier: '', value: undefined })
|
|
|
|
|
+}
|
|
|
|
|
+const removeParameter = (index: number) => {
|
|
|
|
|
+ parameters.value.splice(index, 1)
|
|
|
|
|
+}
|
|
|
// 初始化设备控制执行器结构
|
|
// 初始化设备控制执行器结构
|
|
|
const initDeviceControlConfig = () => {
|
|
const initDeviceControlConfig = () => {
|
|
|
if (!deviceControlConfig.value) {
|
|
if (!deviceControlConfig.value) {
|
|
@@ -100,63 +98,94 @@ const initDeviceControlConfig = () => {
|
|
|
data: {}
|
|
data: {}
|
|
|
} as ActionDeviceControl
|
|
} as ActionDeviceControl
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 确保data对象存在
|
|
|
|
|
+ if (!deviceControlConfig.value.data) {
|
|
|
|
|
+ deviceControlConfig.value.data = {}
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 初始化
|
|
// 初始化
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
initDeviceControlConfig()
|
|
initDeviceControlConfig()
|
|
|
|
|
+ if (props.productId) {
|
|
|
|
|
+ getThingModelTSL()
|
|
|
|
|
+ }
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
-// 产品和设备选择
|
|
|
|
|
-const productTableSelectRef = ref<InstanceType<typeof ProductTableSelect>>()
|
|
|
|
|
-const deviceTableSelectRef = ref<InstanceType<typeof DeviceTableSelect>>()
|
|
|
|
|
-const product = ref<ProductVO>()
|
|
|
|
|
-const deviceList = ref<DeviceVO[]>([])
|
|
|
|
|
-
|
|
|
|
|
-/** 处理产品选择 */
|
|
|
|
|
-const handleProductSelect = (val: ProductVO) => {
|
|
|
|
|
- product.value = val
|
|
|
|
|
- deviceControlConfig.value.productKey = val.productKey
|
|
|
|
|
- deviceList.value = []
|
|
|
|
|
- getThingModelTSL()
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 监听productId变化
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => props.productId,
|
|
|
|
|
+ (newVal) => {
|
|
|
|
|
+ if (newVal) {
|
|
|
|
|
+ getThingModelTSL()
|
|
|
|
|
+ // 当产品ID变化时,清空原有数据
|
|
|
|
|
+ deviceControlConfig.value.data = {}
|
|
|
|
|
+ } else {
|
|
|
|
|
+ thingModelTSL.value = undefined
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
|
|
|
|
|
-/** 处理设备选择 */
|
|
|
|
|
-const handleDeviceSelect = (val: DeviceVO[]) => {
|
|
|
|
|
- deviceList.value = val
|
|
|
|
|
- deviceControlConfig.value.deviceNames = val.map((item) => item.deviceName)
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// 监听消息类型变化
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => deviceControlConfig.value.type,
|
|
|
|
|
+ () => {
|
|
|
|
|
+ // 切换消息类型时清空参数
|
|
|
|
|
+ deviceControlConfig.value.data = {}
|
|
|
|
|
+ if (deviceControlConfig.value.type === IotDeviceMessageTypeEnum.PROPERTY) {
|
|
|
|
|
+ deviceControlConfig.value.identifier = IotDeviceMessageIdentifierEnum.PROPERTY_SET
|
|
|
|
|
+ } else {
|
|
|
|
|
+ deviceControlConfig.value.identifier = ''
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+)
|
|
|
|
|
|
|
|
-/** 打开设备选择器 */
|
|
|
|
|
-const openDeviceSelect = () => {
|
|
|
|
|
- if (!product.value) {
|
|
|
|
|
- message.warning('请先选择一个产品')
|
|
|
|
|
- return
|
|
|
|
|
|
|
+// 监听identifier变化
|
|
|
|
|
+watch(
|
|
|
|
|
+ () => deviceControlConfig.value.identifier,
|
|
|
|
|
+ () => {
|
|
|
|
|
+ // 切换identifier时清空参数
|
|
|
|
|
+ deviceControlConfig.value.data = {}
|
|
|
}
|
|
}
|
|
|
- deviceTableSelectRef.value?.open()
|
|
|
|
|
-}
|
|
|
|
|
|
|
+)
|
|
|
|
|
|
|
|
/** 获取产品物模型 */
|
|
/** 获取产品物模型 */
|
|
|
const thingModelTSL = ref<any>()
|
|
const thingModelTSL = ref<any>()
|
|
|
const getThingModelTSL = async () => {
|
|
const getThingModelTSL = async () => {
|
|
|
- if (!product.value) {
|
|
|
|
|
|
|
+ if (!props.productId) {
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
- thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(product.value.id)
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(props.productId)
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('获取物模型失败', error)
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-/** 根据消息类型和标识符获取对应的物模型 */
|
|
|
|
|
-const getThingModels = () => {
|
|
|
|
|
- if (!deviceControlConfig.value) return []
|
|
|
|
|
-
|
|
|
|
|
|
|
+const thingModels = computed((): any[] => {
|
|
|
switch (deviceControlConfig.value.type) {
|
|
switch (deviceControlConfig.value.type) {
|
|
|
case IotDeviceMessageTypeEnum.PROPERTY:
|
|
case IotDeviceMessageTypeEnum.PROPERTY:
|
|
|
- return thingModelTSL.value?.properties || []
|
|
|
|
|
|
|
+ return thingModelTSL.value.properties
|
|
|
|
|
+ // TODO puhui999: 服务和事件后续考虑
|
|
|
case IotDeviceMessageTypeEnum.SERVICE:
|
|
case IotDeviceMessageTypeEnum.SERVICE:
|
|
|
- return thingModelTSL.value?.services.find(
|
|
|
|
|
- (s: any) => s.identifier === deviceControlConfig.value.identifier
|
|
|
|
|
- ) || {}
|
|
|
|
|
|
|
+ return thingModelTSL.value.services
|
|
|
|
|
+ case IotDeviceMessageTypeEnum.EVENT:
|
|
|
|
|
+ return thingModelTSL.value.events
|
|
|
}
|
|
}
|
|
|
return []
|
|
return []
|
|
|
-}
|
|
|
|
|
-</script>
|
|
|
|
|
|
|
+})
|
|
|
|
|
+/** 获得属性单位 */
|
|
|
|
|
+const getUnitName = computed(() => (identifier: string) => {
|
|
|
|
|
+ const model = thingModels.value?.find((item: any) => item.identifier === identifier)
|
|
|
|
|
+ // 属性
|
|
|
|
|
+ if (model?.dataSpecs) {
|
|
|
|
|
+ return model.dataSpecs.unitName
|
|
|
|
|
+ }
|
|
|
|
|
+ // TODO puhui999: 先不考虑服务和事件的情况
|
|
|
|
|
+ // 服务和事件
|
|
|
|
|
+ // if (model?.outputParams) {
|
|
|
|
|
+ // return model.dataSpecs.unitName
|
|
|
|
|
+ // }
|
|
|
|
|
+ return ''
|
|
|
|
|
+})
|
|
|
|
|
+</script>
|