From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue | 420 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 420 insertions(+), 0 deletions(-)
diff --git a/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue b/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
new file mode 100644
index 0000000..599de70
--- /dev/null
+++ b/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
@@ -0,0 +1,420 @@
+<!-- 妯℃嫙璁惧 -->
+<template>
+ <ContentWrap>
+ <el-row :gutter="20">
+ <!-- 宸︿晶鎸囦护璋冭瘯鍖哄煙 -->
+ <el-col :span="12">
+ <el-tabs v-model="activeTab" type="border-card">
+ <!-- 涓婅鎸囦护璋冭瘯 -->
+ <el-tab-pane label="涓婅鎸囦护璋冭瘯" name="upstream">
+ <el-tabs v-if="activeTab === 'upstream'" v-model="upstreamTab">
+ <!-- 灞炴�т笂鎶� -->
+ <el-tab-pane label="灞炴�т笂鎶�" :name="IotDeviceMessageMethodEnum.PROPERTY_POST.method">
+ <ContentWrap>
+ <el-table :data="propertyList" :show-overflow-tooltip="true" :stripe="true">
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鍔熻兘鍚嶇О"
+ prop="name"
+ width="120"
+ />
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鏍囪瘑绗�"
+ prop="identifier"
+ width="120"
+ />
+ <el-table-column align="center" label="鏁版嵁绫诲瀷" width="100">
+ <template #default="{ row }">
+ {{ row.property?.dataType ?? '-' }}
+ </template>
+ </el-table-column>
+ <el-table-column align="left" label="鏁版嵁瀹氫箟" min-width="200">
+ <template #default="{ row }">
+ <DataDefinition :data="row" />
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" align="center" label="鍊�" width="150">
+ <template #default="scope">
+ <el-input
+ :model-value="getFormValue(scope.row.identifier)"
+ @update:model-value="setFormValue(scope.row.identifier, $event)"
+ placeholder="杈撳叆鍊�"
+ size="small"
+ />
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="flex justify-between items-center mt-4">
+ <span class="text-sm text-gray-600">
+ 璁剧疆灞炴�у�煎悗锛岀偣鍑汇�屽彂閫佸睘鎬т笂鎶ャ�嶆寜閽�
+ </span>
+ <el-button type="primary" @click="handlePropertyPost">鍙戦�佸睘鎬т笂鎶�</el-button>
+ </div>
+ </ContentWrap>
+ </el-tab-pane>
+
+ <!-- 浜嬩欢涓婃姤 -->
+ <el-tab-pane label="浜嬩欢涓婃姤" :name="IotDeviceMessageMethodEnum.EVENT_POST.method">
+ <ContentWrap>
+ <el-table :data="eventList" :show-overflow-tooltip="true" :stripe="true">
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鍔熻兘鍚嶇О"
+ prop="name"
+ width="120"
+ />
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鏍囪瘑绗�"
+ prop="identifier"
+ width="120"
+ />
+ <el-table-column align="center" label="鏁版嵁绫诲瀷" width="100">
+ <template #default="{ row }">
+ {{ row.event?.dataType ?? '-' }}
+ </template>
+ </el-table-column>
+ <el-table-column align="left" label="鏁版嵁瀹氫箟" min-width="200">
+ <template #default="{ row }">
+ <DataDefinition :data="row" />
+ </template>
+ </el-table-column>
+ <el-table-column align="center" label="鍊�" width="200">
+ <template #default="scope">
+ <el-input
+ :model-value="getFormValue(scope.row.identifier)"
+ @update:model-value="setFormValue(scope.row.identifier, $event)"
+ type="textarea"
+ :rows="3"
+ placeholder="杈撳叆浜嬩欢鍙傛暟锛圝SON鏍煎紡锛�"
+ size="small"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" align="center" label="鎿嶄綔" width="100">
+ <template #default="scope">
+ <el-button type="primary" size="small" @click="handleEventPost(scope.row)">
+ 涓婃姤浜嬩欢
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </ContentWrap>
+ </el-tab-pane>
+
+ <!-- 鐘舵�佸彉鏇� -->
+ <el-tab-pane label="鐘舵�佸彉鏇�" :name="IotDeviceMessageMethodEnum.STATE_UPDATE.method">
+ <ContentWrap>
+ <div class="flex gap-4">
+ <el-button type="primary" @click="handleDeviceState(DeviceStateEnum.ONLINE)">
+ 璁惧涓婄嚎
+ </el-button>
+ <el-button type="danger" @click="handleDeviceState(DeviceStateEnum.OFFLINE)">
+ 璁惧涓嬬嚎
+ </el-button>
+ </div>
+ </ContentWrap>
+ </el-tab-pane>
+ </el-tabs>
+ </el-tab-pane>
+
+ <!-- 涓嬭鎸囦护璋冭瘯 -->
+ <el-tab-pane label="涓嬭鎸囦护璋冭瘯" name="downstream">
+ <el-tabs v-if="activeTab === 'downstream'" v-model="downstreamTab">
+ <!-- 灞炴�ц皟璇� -->
+ <el-tab-pane label="灞炴�ц缃�" :name="IotDeviceMessageMethodEnum.PROPERTY_SET.method">
+ <ContentWrap>
+ <el-table :data="propertyList" :show-overflow-tooltip="true" :stripe="true">
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鍔熻兘鍚嶇О"
+ prop="name"
+ width="120"
+ />
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鏍囪瘑绗�"
+ prop="identifier"
+ width="120"
+ />
+ <el-table-column align="center" label="鏁版嵁绫诲瀷" width="100">
+ <template #default="{ row }">
+ {{ row.property?.dataType ?? '-' }}
+ </template>
+ </el-table-column>
+ <el-table-column align="left" label="鏁版嵁瀹氫箟" min-width="200">
+ <template #default="{ row }">
+ <DataDefinition :data="row" />
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" align="center" label="鍊�" width="150">
+ <template #default="scope">
+ <el-input
+ :model-value="getFormValue(scope.row.identifier)"
+ @update:model-value="setFormValue(scope.row.identifier, $event)"
+ placeholder="杈撳叆鍊�"
+ size="small"
+ />
+ </template>
+ </el-table-column>
+ </el-table>
+ <div class="flex justify-between items-center mt-4">
+ <span class="text-sm text-gray-600">
+ 璁剧疆灞炴�у�煎悗锛岀偣鍑汇�屽彂閫佸睘鎬ц缃�嶆寜閽�
+ </span>
+ <el-button type="primary" @click="handlePropertySet">鍙戦�佸睘鎬ц缃�</el-button>
+ </div>
+ </ContentWrap>
+ </el-tab-pane>
+
+ <!-- 鏈嶅姟璋冪敤 -->
+ <el-tab-pane
+ label="璁惧鏈嶅姟璋冪敤"
+ :name="IotDeviceMessageMethodEnum.SERVICE_INVOKE.method"
+ >
+ <ContentWrap>
+ <el-table :data="serviceList" :show-overflow-tooltip="true" :stripe="true">
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鏈嶅姟鍚嶇О"
+ prop="name"
+ width="120"
+ />
+ <el-table-column
+ fixed="left"
+ align="center"
+ label="鏍囪瘑绗�"
+ prop="identifier"
+ width="120"
+ />
+ <el-table-column align="left" label="杈撳叆鍙傛暟" min-width="200">
+ <template #default="{ row }">
+ <DataDefinition :data="row" />
+ </template>
+ </el-table-column>
+ <el-table-column align="center" label="鍙傛暟鍊�" width="200">
+ <template #default="scope">
+ <el-input
+ :model-value="getFormValue(scope.row.identifier)"
+ @update:model-value="setFormValue(scope.row.identifier, $event)"
+ type="textarea"
+ :rows="3"
+ placeholder="杈撳叆鏈嶅姟鍙傛暟锛圝SON鏍煎紡锛�"
+ size="small"
+ />
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" align="center" label="鎿嶄綔" width="100">
+ <template #default="scope">
+ <el-button
+ type="primary"
+ size="small"
+ @click="handleServiceInvoke(scope.row)"
+ >
+ 鏈嶅姟璋冪敤
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </ContentWrap>
+ </el-tab-pane>
+ </el-tabs>
+ </el-tab-pane>
+ </el-tabs>
+ </el-col>
+
+ <!-- 鍙充晶璁惧鏃ュ織鍖哄煙 -->
+ <el-col :span="12">
+ <ContentWrap title="璁惧娑堟伅">
+ <DeviceDetailsMessage ref="deviceMessageRef" :device-id="device.id" />
+ </ContentWrap>
+ </el-col>
+ </el-row>
+ </ContentWrap>
+</template>
+
+<script lang="ts" setup>
+import { ProductVO } from '@/api/iot/product/product'
+import { ThingModelData } from '@/api/iot/thingmodel'
+import { DeviceApi, DeviceStateEnum, DeviceVO } from '@/api/iot/device/device'
+import DeviceDetailsMessage from './DeviceDetailsMessage.vue'
+import { DataDefinition } from '@/views/iot/thingmodel/components'
+import { IotDeviceMessageMethodEnum, IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
+
+const props = defineProps<{
+ product: ProductVO
+ device: DeviceVO
+ thingModelList: ThingModelData[]
+}>()
+
+const message = useMessage() // 娑堟伅寮圭獥
+const activeTab = ref('upstream') // 涓婅upstream銆佷笅琛宒ownstream
+const upstreamTab = ref(IotDeviceMessageMethodEnum.PROPERTY_POST.method) // 涓婅瀛愭爣绛�
+const downstreamTab = ref(IotDeviceMessageMethodEnum.PROPERTY_SET.method) // 涓嬭瀛愭爣绛�
+const deviceMessageRef = ref() // 璁惧娑堟伅缁勪欢寮曠敤
+const deviceMessageRefreshDelay = 2000 // 寤惰繜 N 绉掞紝淇濊瘉妯℃嫙涓婅鐨勬秷鎭澶勭悊
+
+// 琛ㄥ崟鏁版嵁锛氬瓨鍌ㄧ敤鎴疯緭鍏ョ殑妯℃嫙鍊�
+const formData = ref<Record<string, string>>({})
+
+// 鏍规嵁绫诲瀷杩囨护鐗╂ā鍨嬫暟鎹�
+const getFilteredThingModelList = (type: number) => {
+ return props.thingModelList.filter((item) => item.type === type)
+}
+const propertyList = computed(() => getFilteredThingModelList(IoTThingModelTypeEnum.PROPERTY))
+const eventList = computed(() => getFilteredThingModelList(IoTThingModelTypeEnum.EVENT))
+const serviceList = computed(() => getFilteredThingModelList(IoTThingModelTypeEnum.SERVICE))
+
+/** 鑾峰彇琛ㄥ崟鍊肩殑杈呭姪鍑芥暟 */
+const getFormValue = (identifier: string | number | undefined) => {
+ if (!identifier) return ''
+ return formData.value[String(identifier)] || ''
+}
+/** 璁剧疆琛ㄥ崟鍊肩殑杈呭姪鍑芥暟 */
+const setFormValue = (identifier: string | number | undefined, value: string) => {
+ if (!identifier) return
+ formData.value[String(identifier)] = value
+}
+
+/** 妯℃嫙灞炴�т笂鎶� */
+const handlePropertyPost = async () => {
+ const data: Record<string, any> = {}
+ propertyList.value.forEach((item) => {
+ const value = getFormValue(item.identifier)
+ if (value && item.identifier) {
+ data[String(item.identifier)] = value
+ }
+ })
+ if (Object.keys(data).length === 0) {
+ message.warning('璇疯嚦灏戣缃竴涓睘鎬у��')
+ return
+ }
+
+ try {
+ await DeviceApi.sendDeviceMessage({
+ deviceId: props.device.id,
+ method: IotDeviceMessageMethodEnum.PROPERTY_POST.method,
+ params: data
+ })
+ message.success('灞炴�т笂鎶ユ垚鍔�')
+ deviceMessageRef.value.refresh(deviceMessageRefreshDelay)
+ } catch (error) {
+ message.error('灞炴�т笂鎶ュけ璐�')
+ }
+}
+
+/** 妯℃嫙浜嬩欢涓婃姤 */
+const handleEventPost = async (eventItem: ThingModelData) => {
+ const value = getFormValue(eventItem.identifier)
+ if (!value) {
+ message.warning('璇疯緭鍏ヤ簨浠跺弬鏁�')
+ return
+ }
+ let eventParams: any
+ try {
+ eventParams = JSON.parse(value)
+ } catch {
+ message.error('浜嬩欢鍙傛暟鏍煎紡涓嶆纭紝璇疯緭鍏ユ湁鏁堢殑JSON鏍煎紡')
+ return
+ }
+
+ try {
+ await DeviceApi.sendDeviceMessage({
+ deviceId: props.device.id,
+ method: IotDeviceMessageMethodEnum.EVENT_POST.method,
+ params: {
+ identifier: String(eventItem.identifier),
+ value: eventParams,
+ time: Date.now()
+ }
+ })
+ message.success(`浜嬩欢銆�${String(eventItem.name)}銆戜笂鎶ユ垚鍔焋)
+ deviceMessageRef.value.refresh(deviceMessageRefreshDelay)
+ } catch (error) {
+ message.error(`浜嬩欢銆�${String(eventItem.name)}銆戜笂鎶ュけ璐)
+ }
+}
+
+/** 妯℃嫙璁惧鐘舵�� */
+const handleDeviceState = async (state: number) => {
+ try {
+ await DeviceApi.sendDeviceMessage({
+ deviceId: props.device.id,
+ method: IotDeviceMessageMethodEnum.STATE_UPDATE.method,
+ params: {
+ state: state
+ }
+ })
+ message.success(`璁惧${state === DeviceStateEnum.ONLINE ? '涓婄嚎' : '涓嬬嚎'}鎴愬姛`)
+ deviceMessageRef.value.refresh(deviceMessageRefreshDelay)
+ } catch (error) {
+ message.error(`璁惧${state === DeviceStateEnum.ONLINE ? '涓婄嚎' : '涓嬬嚎'}澶辫触`)
+ }
+}
+
+/** 妯℃嫙灞炴�ц缃� */
+const handlePropertySet = async () => {
+ const data: Record<string, any> = {}
+ propertyList.value.forEach((item) => {
+ const value = getFormValue(item.identifier)
+ if (value && item.identifier) {
+ data[String(item.identifier)] = value
+ }
+ })
+ if (Object.keys(data).length === 0) {
+ message.warning('璇疯嚦灏戣缃竴涓睘鎬у��')
+ return
+ }
+
+ try {
+ await DeviceApi.sendDeviceMessage({
+ deviceId: props.device.id,
+ method: IotDeviceMessageMethodEnum.PROPERTY_SET.method,
+ params: data
+ })
+ message.success('灞炴�ц缃垚鍔�')
+ deviceMessageRef.value.refresh(deviceMessageRefreshDelay)
+ } catch (error) {
+ message.error('灞炴�ц缃け璐�')
+ }
+}
+
+/** 妯℃嫙鏈嶅姟璋冪敤 */
+const handleServiceInvoke = async (serviceItem: ThingModelData) => {
+ const value = getFormValue(serviceItem.identifier)
+ if (!value) {
+ message.warning('璇疯緭鍏ユ湇鍔″弬鏁�')
+ return
+ }
+ let serviceParams: any
+ try {
+ serviceParams = JSON.parse(value)
+ } catch {
+ message.error('鏈嶅姟鍙傛暟鏍煎紡涓嶆纭紝璇疯緭鍏ユ湁鏁堢殑JSON鏍煎紡')
+ return
+ }
+
+ try {
+ await DeviceApi.sendDeviceMessage({
+ deviceId: props.device.id,
+ method: IotDeviceMessageMethodEnum.SERVICE_INVOKE.method,
+ params: {
+ identifier: String(serviceItem.identifier),
+ inputParams: serviceParams
+ }
+ })
+ message.success(`鏈嶅姟銆�${String(serviceItem.name)}銆戣皟鐢ㄦ垚鍔焋)
+ deviceMessageRef.value.refresh(deviceMessageRefreshDelay)
+ } catch (error) {
+ message.error(`鏈嶅姟銆�${String(serviceItem.name)}銆戣皟鐢ㄥけ璐)
+ }
+}
+</script>
--
Gitblit v1.8.0