| 
					
				 | 
			
			
				@@ -0,0 +1,406 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  <div class="device-monitor-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ <!-- 实时数据页面 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <div v-show="activeTab === 'realtime'" class="tab-content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-card class="box-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div slot="header" class="clearfix"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <span>实时数据</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-button style="float: right; padding: 3px 0" type="text" @click="refreshRealtimeData"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <i class="el-icon-refresh"></i> 刷新 ({{ realtimeCountdown }}s) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 数据分组展示 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="realtime-groups"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-row :gutter="20"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :span="8" v-for="group in realtimeGroups" :key="group.groupName"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-card class="group-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div slot="header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <span>{{ group.groupName }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-badge :value="group.points.length" class="point-count"></el-badge> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="point-list"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <div v-for="point in group.points" :key="point.pointId" class="point-item"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <div class="point-name">{{ point.pointName }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <div class="point-value"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <span :class="['value', getPointStatusClass(point.status)]"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        {{ point.value }} {{ point.unit }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      </span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <el-tag :type="getPointStatusTag(point.status)" size="mini"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        {{ getPointStatusText(point.status) }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <div class="point-time">{{ point.updateTime }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import * as echarts from 'echarts' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export default { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  name: 'DeviceMonitor', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  data() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 设备选择 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceForm: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        deviceId: '', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        deviceType: '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceList: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 当前活动页签 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      activeTab: 'control', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 实时数据相关 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      realtimeGroups: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      realtimeCountdown: 30, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      realtimeTimer: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 设备详情相关 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceDetail: {}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      deviceDocuments: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      showUploadDialog: false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      fileList: [], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      uploadUrl: '/api/device/upload', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      uploadHeaders: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        'Authorization': 'Bearer ' + this.getToken() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  mounted() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.loadDeviceList() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.initRealtimeTimer() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  methods: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 获取设备列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async loadDeviceList() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const response = await this.$deviceApi.getDeviceList() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deviceList = response.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.error('获取设备列表失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 页签切换 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleTabClick(tab) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.loadCurrentTabData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 加载当前页签数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    loadCurrentTabData() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!this.deviceForm.deviceId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.warning('请先选择设备') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      switch (this.activeTab) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'control': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadControlRecords() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'realtime': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadRealtimeData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'history': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadHistoryData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadAvailablePoints() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'events': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadEventRecords() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        case 'details': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadDeviceDetail() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadDeviceDocuments() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // ========== 实时数据相关方法 ========== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async loadRealtimeData() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const response = await this.$deviceApi.getRealtimeData({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          deviceId: this.deviceForm.deviceId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.realtimeGroups = response.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.error('获取实时数据失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    refreshRealtimeData() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.loadRealtimeData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.realtimeCountdown = 30 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    initRealtimeTimer() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.realtimeTimer = setInterval(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.realtimeCountdown-- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (this.realtimeCountdown <= 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (this.activeTab === 'realtime' && this.deviceForm.deviceId) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.refreshRealtimeData() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.realtimeCountdown = 30 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }, 1000) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getPointStatusClass(status) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return status === 'normal' ? 'normal' : 'abnormal' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getPointStatusTag(status) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return status === 'normal' ? 'success' : 'danger' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getPointStatusText(status) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return status === 'normal' ? '正常' : '异常' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // ========== 设备详情相关方法 ========== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async loadDeviceDetail() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const response = await this.$deviceApi.getDeviceDetail({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          deviceId: this.deviceForm.deviceId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deviceDetail = response.data || {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.error('获取设备详情失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async loadDeviceDocuments() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const response = await this.$deviceApi.getDeviceDocuments({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          deviceId: this.deviceForm.deviceId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.deviceDocuments = response.data || [] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.error('获取设备文档失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    formatFileSize(bytes) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (bytes === 0) return '0 Bytes' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const k = 1024 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const sizes = ['Bytes', 'KB', 'MB', 'GB'] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const i = Math.floor(Math.log(bytes) / Math.log(k)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    beforeUpload(file) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const isLt10M = file.size / 1024 / 1024 < 10 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (!isLt10M) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.error('上传文件大小不能超过 10MB!') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return isLt10M 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleUploadSuccess(response, file) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.$message.success('上传成功') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.loadDeviceDocuments() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    handleUploadError(error, file) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.$message.error('上传失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    submitUpload() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.$refs.upload.submit() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.showUploadDialog = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    async downloadFile(file) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const response = await this.$deviceApi.downloadFile({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          fileId: file.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const url = window.URL.createObjectURL(new Blob([response.data])) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const link = document.createElement('a') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        link.href = url 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        link.setAttribute('download', file.fileName) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        document.body.appendChild(link) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        link.click() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        document.body.removeChild(link) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        window.URL.revokeObjectURL(url) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.error('下载失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    deleteFile(file) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.$confirm('确认删除该文件?', '提示', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '确定', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: 'warning' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).then(async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          await this.$deviceApi.deleteDocument({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fileId: file.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.$message.success('删除成功') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.loadDeviceDocuments() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.$message.error('删除失败') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).catch(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.$message.info('已取消删除') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 获取认证token 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    getToken() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return localStorage.getItem('token') || sessionStorage.getItem('token') || '' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<style scoped> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-monitor-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-selector { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.function-tabs { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.tab-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  min-height: 500px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 实时数据样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.realtime-groups { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-top: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.group-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-count { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-left: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-list { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  max-height: 300px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  overflow-y: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 10px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: 1px solid #f0f0f0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-item:last-child { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-bottom: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: bold; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  text-align: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-value .value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-right: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-value .value.normal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #67C23A; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-value .value.abnormal { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #F56C6C; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.point-time { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  text-align: right; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #999; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 图表容器 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.chart-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 20px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border: 1px solid #dcdfe6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  border-radius: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 时间轴样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.timeline-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  max-height: 600px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  overflow-y: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.event-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-bottom: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.event-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-weight: bold; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin-right: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.event-content p { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 5px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 设备信息样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.device-info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 上传对话框样式 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.dialog-footer { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  text-align: right; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* 响应式布局 */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@media (max-width: 768px) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .device-monitor-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .realtime-groups .el-col { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .point-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    align-items: flex-start; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .point-value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    text-align: left; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin: 5px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</style> 
			 |