| 
					
				 | 
			
			
				@@ -1,172 +1,1586 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  <div class="app-container home"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <el-row :gutter="20"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <!-- 左侧内容 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <el-col :sm="24" :lg="12" style="padding-left: 20px"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <h2>IBMS后台管理框架</h2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <b>当前版本:</b> <span>v{{ version }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        </p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  <div class="dashboard-container"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 顶部欢迎区域 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <div class="welcome-section"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <div class="welcome-content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <h1 class="welcome-title"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <span class="gradient-text">IBMS智能建筑管理系统</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </h1> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p class="welcome-subtitle">集成化、智能化、可视化的建筑管理解决方案</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="version-info"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-tag type="primary" effect="dark" @click="showVersionInfo"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <i class="el-icon-price-tag"></i> v{{ version }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-tag type="success" effect="plain" @click="showSystemStatus"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <i class="el-icon-circle-check"></i> 运行正常 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <div class="welcome-illustration"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- SVG 图形保持不变 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <svg viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <defs> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <stop offset="0%" style="stop-color:#667eea;stop-opacity:0.8" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <stop offset="100%" style="stop-color:#764ba2;stop-opacity:0.8" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </linearGradient> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </defs> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 建筑轮廓 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="50" y="100" width="80" height="150" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2" rx="5"/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="150" y="50" width="100" height="200" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2" rx="5"/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="270" y="120" width="80" height="130" fill="rgba(255,255,255,0.2)" stroke="white" stroke-width="2" rx="5"/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 窗户 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="60" y="110" width="20" height="20" fill="rgba(255,255,255,0.5)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="90" y="110" width="20" height="20" fill="rgba(255,255,255,0.5)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="60" y="140" width="20" height="20" fill="rgba(255,255,255,0.5)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <rect x="90" y="140" width="20" height="20" fill="rgba(255,255,255,0.5)" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 连接线 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <path d="M 90 250 Q 200 280 310 250" stroke="white" stroke-width="2" fill="none" stroke-dasharray="5,5" opacity="0.5"/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <circle cx="200" cy="265" r="5" fill="white" opacity="0.8"/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <!-- 右侧技术选型 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <el-col :sm="24" :lg="12" style="padding-left: 50px"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <el-col :span="12"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <h2>技术选型</h2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <el-col :span="6"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <h4>后端技术</h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <ul> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <li v-for="(item, index) in backendTech" :key="index">{{ item }}</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            </ul> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <el-col :span="6"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <h4>前端技术</h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            <ul> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              <li v-for="(item, index) in frontendTech" :key="index">{{ item }}</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            </ul> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <!-- 图标 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <text x="200" y="40" text-anchor="middle" fill="white" font-size="24" font-weight="bold">IBMS</text> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </svg> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 快速统计卡片 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <el-row :gutter="20" class="stat-cards"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-col :xs="24" :sm="12" :md="6" v-for="(stat, index) in statistics" :key="index"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <div class="stat-card" :style="{ background: stat.color }" @click="handleStatClick(stat)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="stat-icon"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <component :is="stat.iconComponent" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="stat-content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="stat-value"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <span class="count-up">{{ stat.value }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="stat-label">{{ stat.label }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="stat-trend" :class="stat.trend > 0 ? 'up' : 'down'"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <ArrowUp v-if="stat.trend > 0" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <ArrowDown v-else /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            {{ Math.abs(stat.trend) }}% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <el-divider /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <!-- 主要内容区域 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <el-row :gutter="20" class="main-content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <!-- 系统功能模块 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-col :xs="24" :lg="16"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-card class="feature-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="card-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><Menu /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                系统功能模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button type="text" @click="viewAllModules"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                查看全部 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><ArrowRight /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-row :gutter="15"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-col :xs="12" :sm="8" :md="6" v-for="(module, index) in systemModules" :key="index"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="module-item" @click="handleModuleClick(module)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="module-icon" :style="{ background: module.color }"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <component :is="module.iconComponent" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="module-name">{{ module.name }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="module-desc">{{ module.desc }}</div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 实时监控数据 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 实时监控数据 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-card class="monitor-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="card-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><DataLine /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                实时监控数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-button-group> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button size="small" :type="chartType === 'line' ? 'primary' : ''" @click="switchChart('line')"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  折线图 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-button size="small" :type="chartType === 'bar' ? 'primary' : ''" @click="switchChart('bar')"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  柱状图 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-button-group> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="chart-container" @click="viewDetailChart"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <!-- 模拟图表 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="mock-chart"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="chart-bars" v-if="chartType === 'bar'"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-for="(bar, index) in mockChartData" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :key="index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    class="bar" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :style="{ height: bar + '%', animationDelay: index * 0.1 + 's' }" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    @click.stop="showDataDetail(index, bar)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <span class="bar-value">{{ bar }}%</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="chart-lines" v-else> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <!-- 简单的折线图模拟 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <svg width="100%" height="100%" :viewBox="`0 0 ${chartWidth} ${chartHeight}`" preserveAspectRatio="none"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <!-- 网格线 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <g class="grid"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <!-- 水平网格线 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <line v-for="i in 5" :key="'h-' + i" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :x1="0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :y1="(chartHeight / 5) * i" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :x2="chartWidth" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :y2="(chartHeight / 5) * i" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          stroke="#e0e0e0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          stroke-width="1" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <!-- 垂直网格线 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <line v-for="(label, index) in chartLabels" :key="'v-' + index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :x1="getXPosition(index)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :y1="0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :x2="getXPosition(index)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          :y2="chartHeight" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          stroke="#e0e0e0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                          stroke-width="1" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </g> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <!-- 其他内容 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <el-row :gutter="20"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <el-col :span="24"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <h2>更新日志</h2> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        <ol class="update-log"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          <li v-for="(log, index) in updateLogs" :key="index">{{ log }}</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        </ol> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <!-- 折线 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <polyline 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      :points="linePoints" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      fill="none" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      stroke="#409EFF" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      stroke-width="3" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      stroke-linejoin="round" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      stroke-linecap="round" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <!-- 数据点 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <g> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <circle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        v-for="(point, index) in linePointsArray" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :key="index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :cx="point.x" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :cy="point.y" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        r="5" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        fill="#409EFF" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        stroke="white" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        stroke-width="2" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        @click.stop="showDataDetail(index, mockChartData[index])" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        style="cursor: pointer;" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        class="data-point" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <title>{{ chartLabels[index] }}: {{ mockChartData[index] }}%</title> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </circle> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </g> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <!-- 数值标签 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <g> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        v-for="(point, index) in linePointsArray" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :key="'text-' + index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :x="point.x" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        :y="point.y - 10" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        text-anchor="middle" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        font-size="12" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        fill="#606266" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        class="value-label" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      {{ mockChartData[index] }}% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </text> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </g> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </svg> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="chart-labels"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <span v-for="(label, index) in chartLabels" :key="index" @click="showLabelDetail(label)">{{ label }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <!-- 右侧信息栏 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <el-col :xs="24" :lg="8"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 技术栈 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-card class="tech-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="card-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><Cpu /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                技术架构 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-tabs v-model="activeTech" class="tech-tabs"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-tab-pane label="后端技术" name="backend"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="tech-list"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="tech-item" v-for="(tech, index) in backendTech" :key="index" @click="showTechDetail(tech)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-tag :type="tech.type" effect="plain">{{ tech.name }}</el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <span class="tech-version">{{ tech.version }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-tab-pane> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-tab-pane label="前端技术" name="frontend"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <div class="tech-list"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <div class="tech-item" v-for="(tech, index) in frontendTech" :key="index" @click="showTechDetail(tech)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <el-tag :type="tech.type" effect="plain">{{ tech.name }}</el-tag> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <span class="tech-version">{{ tech.version }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-tab-pane> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-tabs> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 系统公告 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-card class="notice-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="card-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><Bell /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                系统公告 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<!--                <el-badge v-if="unreadCount > 0" :value="unreadCount" :max="99" class="notice-badge" />--> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-link type="primary" @click="viewAllNotices">更多</el-link> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <el-skeleton :loading="noticeLoading" animated :count="3"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <template #template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-skeleton-item variant="h3" style="width: 50%; margin-bottom: 10px;" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-skeleton-item variant="text" style="margin-bottom: 5px;" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-skeleton-item variant="text" style="width: 80%; margin-bottom: 20px;" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <template #default> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-timeline v-if="notices.length > 0"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-timeline-item 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    v-for="(notice, index) in notices" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :key="notice.notice_id" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :timestamp="parseTime(notice.create_time)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    :type="getNoticeTimelineType(notice.notice_type)" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    placement="top"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  <div class="notice-content"><!-- @click="viewNoticeDetail(notice)--> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      {{ notice.notice_title }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<!--                      <el-tag v-if="!notice.is_read" type="danger" size="small" effect="plain">未读</el-tag>--> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </h4> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <p>{{ getNoticePreview(notice.notice_content) }}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <div class="notice-meta"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    <span class="notice-type"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <dict-tag :options="sys_notice_type" :value="notice.notice_type" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      <span class="notice-author">{{ notice.create_by }}</span> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                </el-timeline-item> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-timeline> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-empty v-else description="暂无公告" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </el-skeleton> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <!-- 快捷操作 --> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <el-card class="quick-action-card"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <template #header> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <div class="card-header"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <el-icon><Lightning /></el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                快捷操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </h3> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div class="quick-actions"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            <el-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                v-for="(action, index) in quickActions" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :key="index" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                :type="action.type" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                @click="handleQuickAction(action)"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              <el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                <component :is="action.iconComponent" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              </el-icon> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              {{ action.name }} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            </el-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </el-card> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       </el-col> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     </el-row> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-<script setup name="Index"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { ref } from 'vue'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<script setup name="Dashboard"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Monitor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Connection, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Lightning, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Warning, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Menu, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ArrowRight, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  DataLine, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Cpu, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Bell, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ArrowUp, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ArrowDown, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  VideoCamera, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Search, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Document, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Setting, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  Download, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  PartlyCloudy 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} from '@element-plus/icons-vue'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 导入必要的API和工具 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ref, reactive, onMounted, onUnmounted, shallowRef, computed } from 'vue'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { useRouter } from 'vue-router'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ElMessage, ElMessageBox, ElNotification } from 'element-plus'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { getNotice, show as markNoticeAsRead } from "@/api/system/notice"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import {listNoticeRead} from "@/api/system/menu"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { connectToWebSocket } from "@/layout/components/websocket"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取字典数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const { proxy } = getCurrentInstance(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const { sys_notice_status, sys_notice_type } = proxy.useDict("sys_notice_status", "sys_notice_type"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const router = useRouter(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const version = ref('3.8.9'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const activeTech = ref('backend'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const chartType = ref('bar'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 后端技术列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-const backendTech = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'SpringBoot', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Spring Security', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'JWT', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'MyBatis', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Druid', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Fastjson', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  '...' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 前端技术列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-const frontendTech = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Vue', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Vuex', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Element-ui', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Axios', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Sass', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  'Quill', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  '...' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 更新日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-const updateLogs = [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  '修复了一些已知问题', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  '优化了性能', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  '新增了用户管理模块', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  '...' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 系统公告相关的响应式数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const notices = ref([]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const noticeLoading = ref(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const unreadCount = ref(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const noticeDialogVisible = ref(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const currentNotice = ref({}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-<style scoped lang="scss"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-.home { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  background: #f0f4f8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  color: #333; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  font-family: 'Roboto', sans-serif; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  min-height: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// WebSocket连接 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let wsConnection = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 查询参数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const noticeQueryParams = ref({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pageNum: 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pageSize: 5,  // Dashboard只显示最新5条 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  orderByColumn: 'create_time', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  isAsc: 'desc' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  h2 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    font-size: 26px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    font-weight: bold; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    margin-bottom: 15px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取公告列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getNoticeList = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  noticeLoading.value = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await listNoticeRead(noticeQueryParams.value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 获取前5条公告 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      notices.value = response.data.slice(0, 3); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 计算未读数量 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      unreadCount.value = response.data.filter(item => !item.is_read).length; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取公告列表失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取公告列表失败'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } finally { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    noticeLoading.value = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取公告预览内容(去除HTML标签,限制长度) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getNoticePreview = (content) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!content) return ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 去除HTML标签 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const text = content.replace(/<[^>]*>/g, ''); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 限制长度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return text.length > 50 ? text.substring(0, 50) + '...' : text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    margin-top: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 根据公告类型返回时间线类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getNoticeTimelineType = (noticeType) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const typeMap = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    '1': 'primary',   // 通知 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    '2': 'success',   // 公告 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    '3': 'warning',   // 提醒 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    '4': 'danger'     // 紧急 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return typeMap[noticeType] || 'info'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    b { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      font-weight: bold; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 查看公告详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/*const viewNoticeDetail = async (notice) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await getNotice(notice.notice_id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      currentNotice.value = response.data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessageBox.alert( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          `<div style="text-align: left;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <p><strong>公告标题:</strong>${response.data.noticeTitle}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <p><strong>公告类型:</strong>${getNoticeTypeLabel(response.data.noticeType)}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <p><strong>发布人:</strong>${response.data.createBy}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <p><strong>发布时间:</strong>${response.data.createTime}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <p><strong>公告内容:</strong></p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          <div style="margin-top: 10px; padding: 10px; background: #f5f7fa; border-radius: 4px;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ${response.data.noticeContent} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        </div>`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          '公告详情', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dangerouslyUseHTMLString: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            confirmButtonText: '已读', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            customClass: 'notice-detail-dialog', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            beforeClose: async (action, instance, done) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              if (action === 'confirm' && !notice.is_read) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                await markAsRead(notice.notice_id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              done(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('获取公告详情失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElMessage.error('获取公告详情失败'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+};*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  .el-row { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 标记为已读 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const markAsRead = async (noticeId) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const response = await markNoticeAsRead({ noticeId }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (response.code === 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 刷新公告列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      await getNoticeList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.success('已标记为已读'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    console.error('标记已读失败:', error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  .el-col { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    background: #ffffff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    border-radius: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    transition: transform 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取公告类型标签 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getNoticeTypeLabel = (type) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const dict = sys_notice_type.value.find(item => item.value === type); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return dict ? dict.label : type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 查看所有公告 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const viewAllNotices = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  router.push('/system/notice'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// WebSocket消息处理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleWebSocketMessage = (message) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (message && message !== "del" && message !== "update") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ElNotification({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      title: '新公告', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      message: '您有新的公告,请注意查收', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: 'warning', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      duration: 5000, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      position: 'top-right', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      onClick: () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        getNoticeList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 刷新公告列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getNoticeList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 其他原有的方法保持不变... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 初始化时显示欢迎信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.success('欢迎使用IBMS智能建筑管理系统!'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 获取公告列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getNoticeList(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 连接WebSocket 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  wsConnection = connectToWebSocket(handleWebSocketMessage); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 其他原有的初始化代码... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onUnmounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 清理WebSocket连接 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (wsConnection) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 根据实际的WebSocket实现进行清理 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 图表尺寸 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const chartWidth = ref(600); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const chartHeight = ref(250); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 获取X轴位置 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const getXPosition = (index) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const padding = 40; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const step = (chartWidth.value - 2 * padding) / (chartLabels.length - 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return padding + index * step; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 计算折线图点位 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const linePoints = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const padding = 40; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const xStep = (chartWidth.value - 2 * padding) / (mockChartData.value.length - 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const yRange = chartHeight.value - 2 * padding; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return mockChartData.value.map((value, index) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const x = padding + index * xStep; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const y = chartHeight.value - padding - (value / 100) * yRange; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return `${x},${y}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }).join(' '); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const linePointsArray = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const padding = 40; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const xStep = (chartWidth.value - 2 * padding) / (mockChartData.value.length - 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const yRange = chartHeight.value - 2 * padding; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return mockChartData.value.map((value, index) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    x: padding + index * xStep, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    y: chartHeight.value - padding - (value / 100) * yRange 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 模拟图表数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const mockChartData = ref([65, 78, 90, 70, 85, 60, 75]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const chartLabels = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 统计数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const statistics = reactive([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    label: '设备总数', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value: '1,234', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Monitor), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trend: 12.5, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/device/list' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    label: '在线设备', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value: '1,180', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Connection), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trend: 8.3, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/device/online' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    label: '今日能耗', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value: '2,845', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Lightning), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trend: -5.2, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/energy/today' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    label: '告警数量', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    value: '12', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Warning), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    trend: -15.8, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/alarm/list' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 系统模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const systemModules = reactive([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '能源管理', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    desc: '能耗监控分析', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Lightning), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: '#409EFF', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/energy' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '设备监控', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    desc: '设备状态管理', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Monitor), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: '#67C23A', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/device' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '环境监测', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    desc: '环境参数监控', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(PartlyCloudy), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: '#E6A23C', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/environment' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '安防系统', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    desc: '安全防护管理', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(VideoCamera), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: '#F56C6C', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/security' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '照明控制', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    desc: '智能照明管理', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Lightning), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: '#909399', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/lighting' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '报警管理', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    desc: '告警处理中心', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Bell), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: '#E6A23C', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    path: '/alarm' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 技术栈数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const backendTech = reactive([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Spring Boot', version: '2.7.x', type: 'primary', desc: '基础框架' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Spring Security', version: '5.7.x', type: 'success', desc: '安全框架' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'JWT', version: '0.11.x', type: 'info', desc: '认证方案' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'MyBatis Plus', version: '3.5.x', type: 'warning', desc: 'ORM框架' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Redis', version: '6.2.x', type: 'danger', desc: '缓存中间件' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'MySQL', version: '8.0.x', type: 'primary', desc: '关系型数据库' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'RabbitMQ', version: '3.9.x', type: 'success', desc: '消息队列' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const frontendTech = reactive([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Vue 3', version: '3.3.x', type: 'primary', desc: '前端框架' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Vite', version: '4.4.x', type: 'success', desc: '构建工具' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Element Plus', version: '2.3.x', type: 'info', desc: 'UI组件库' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Pinia', version: '2.1.x', type: 'warning', desc: '状态管理' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'Axios', version: '1.4.x', type: 'danger', desc: 'HTTP客户端' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'ECharts', version: '5.4.x', type: 'primary', desc: '图表库' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { name: 'TypeScript', version: '5.1.x', type: 'success', desc: '类型系统' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 快捷操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const quickActions = reactive([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '设备巡检', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Search), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: 'primary', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    action: 'inspection' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '生成报表', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Document), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: 'success', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    action: 'report' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '系统设置', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Setting), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: 'info', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    action: 'settings' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    name: '数据备份', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    iconComponent: shallowRef(Download), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: 'warning', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    action: 'backup' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 显示版本信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const showVersionInfo = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessageBox.alert( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      `<div style="text-align: left;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>当前版本:</strong>v${version.value}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>发布日期:</strong>2024-01-15</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>更新内容:</strong></p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <ul style="margin-left: 20px;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <li>优化系统性能</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <li>新增能源分析报表</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <li>修复已知问题</li> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </ul> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div>`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      '版本信息', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dangerouslyUseHTMLString: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '确定' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 显示系统状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const showSystemStatus = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessageBox.alert( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      `<div style="text-align: left;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>系统状态:</strong><span style="color: #67C23A;">运行正常</span></p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>运行时长:</strong>15天 8小时 32分钟</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>CPU使用率:</strong>35%</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>内存使用率:</strong>62%</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>磁盘使用率:</strong>48%</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div>`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      '系统状态', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dangerouslyUseHTMLString: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '确定' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理统计卡片点击 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleStatClick = (stat) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.info(`正在查看${stat.label}详情...`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 实际项目中这里应该跳转到对应页面 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // router.push(stat.path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 查看所有模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const viewAllModules = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.success('正在加载所有系统模块...'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // router.push('/modules'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理模块点击 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleModuleClick = (module) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.success(`正在进入${module.name}模块`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 实际项目中这里应该跳转到对应页面 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // router.push(module.path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 切换图表类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const switchChart = (type) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  chartType.value = type; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.success(`已切换为${type === 'line' ? '折线图' : '柱状图'}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 这里可以重新加载图表数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  refreshChartData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 刷新图表数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const refreshChartData = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 模拟数据刷新 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  mockChartData.value = mockChartData.value.map(() => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Math.floor(Math.random() * 40) + 60 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 查看详细图表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const viewDetailChart = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.info('正在打开详细数据分析页面...'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // router.push('/analysis/chart'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 显示数据详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const showDataDetail = (index, value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessageBox.alert( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      `<div style="text-align: left;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>日期:</strong>${chartLabels[index]}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>数值:</strong>${value}%</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>环比:</strong>${index > 0 ? ((value - mockChartData.value[index - 1]) > 0 ? '+' : '') + (value - mockChartData.value[index - 1]).toFixed(1) + '%' : '无'}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>状态:</strong>${value > 80 ? '<span style="color: #F56C6C;">偏高</span>' : value > 60 ? '<span style="color: #E6A23C;">正常</span>' : '<span style="color: #67C23A;">偏低</span>'}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div>`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      '数据详情', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dangerouslyUseHTMLString: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '确定' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 显示标签详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const showLabelDetail = (label) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessage.info(`查看${label}的详细数据`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 显示技术详情 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const showTechDetail = (tech) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ElMessageBox.alert( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      `<div style="text-align: left;"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>技术名称:</strong>${tech.name}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>当前版本:</strong>${tech.version}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>功能描述:</strong>${tech.desc}</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <p><strong>官方网站:</strong><a href="#" style="color: #409EFF;">查看官网</a></p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div>`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      '技术详情', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        dangerouslyUseHTMLString: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '确定' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 处理快捷操作 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const handleQuickAction = (action) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  switch (action.action) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    case 'inspection': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessageBox.confirm('是否立即开始设备巡检?', '设备巡检', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '开始巡检', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: 'info' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).then(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ElMessage.success('设备巡检已开始,预计需要5分钟'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 这里可以调用巡检API 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).catch(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ElMessage.info('已取消设备巡检'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    case 'report': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessageBox.prompt('请选择报表类型', '生成报表', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '生成', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        inputPattern: /^(日报|周报|月报)$/, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        inputPlaceholder: '请输入:日报、周报或月报', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        inputErrorMessage: '请输入正确的报表类型' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).then(({ value }) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ElMessage.success(`正在生成${value},请稍候...`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 模拟生成报表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        setTimeout(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ElMessage.success(`${value}生成成功,已保存到系统`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }, 2000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).catch(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ElMessage.info('已取消生成报表'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    case 'settings': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessage.info('正在打开系统设置...'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // router.push('/settings'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    case 'backup': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ElMessageBox.confirm('确定要备份系统数据吗?', '数据备份', { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        confirmButtonText: '确定备份', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cancelButtonText: '取消', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: 'warning' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).then(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ElMessage.success('数据备份已开始,请勿关闭页面'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 模拟备份进度 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        let progress = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const timer = setInterval(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          progress += 20; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (progress >= 100) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            clearInterval(timer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ElMessage.success('数据备份完成!'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ElMessage.info(`备份进度:${progress}%`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }, 1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }).catch(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ElMessage.info('已取消数据备份'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      transform: translateY(-5px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 数字动画效果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const animateValue = (obj, start, end, duration) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  let startTimestamp = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const step = (timestamp) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!startTimestamp) startTimestamp = timestamp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const progress = Math.min((timestamp - startTimestamp) / duration, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    obj.value = Math.floor(progress * (end - start) + start); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (progress < 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      window.requestAnimationFrame(step); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  window.requestAnimationFrame(step); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 初始化时显示欢迎信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*ElMessage.success('欢迎使用IBMS智能建筑管理系统!');*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 模拟数据更新 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setInterval(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 随机更新一些数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const randomIndex = Math.floor(Math.random() * mockChartData.value.length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mockChartData.value[randomIndex] = Math.floor(Math.random() * 40) + 60; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }, 5000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+</script> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+<style lang="scss" scoped> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.dashboard-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background: #f5f7fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  min-height: calc(100vh - 84px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 欢迎区域 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .welcome-section { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 40px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin-bottom: 30px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    overflow: hidden; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    &::before { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      content: ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      top: -50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      right: -50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      width: 200%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      height: 200%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      animation: pulse 4s ease-in-out infinite; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .welcome-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      z-index: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .welcome-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 36px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .gradient-text { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          background: linear-gradient(to right, #fff, #f0f0f0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          -webkit-background-clip: text; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          -webkit-text-fill-color: transparent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .welcome-subtitle { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 18px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        opacity: 0.9; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .version-info { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .el-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          margin-right: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .welcome-illustration { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      width: 400px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      height: 300px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      z-index: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      svg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        height: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        filter: drop-shadow(0 4px 8px rgba(0,0,0,0.1)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ul { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    list-style-type: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    padding: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 统计卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .stat-cards { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    margin-bottom: 30px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    li { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      line-height: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .stat-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      padding: 25px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      padding-left: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      overflow: hidden; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      height: 140px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        transform: translateY(-5px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .stat-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          transform: scale(1.1) rotate(5deg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       &::before { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        content: '•'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        content: ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        top: -50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        right: -50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width: 200%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        height: 200%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        background: radial-gradient(circle, rgba(255,255,255,0.2) 0%, transparent 70%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .stat-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        left: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        right: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        top: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 48px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        opacity: 0.3; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .stat-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        z-index: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .stat-value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 32px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          margin-bottom: 5px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .count-up { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            display: inline-block; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .stat-label { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          opacity: 0.9; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .stat-trend { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        right: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gap: 5px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        background: rgba(255,255,255,0.2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 4px 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        border-radius: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &.up { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: #67C23A; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &.down { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: #F56C6C; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .el-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  .update-log { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ol { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      padding-left: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 主要内容区域 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .main-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 通用卡片样式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .el-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      border: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      li { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        line-height: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .card-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        h3 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          margin: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 18px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .el-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            color: #409EFF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 功能模块卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .feature-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .module-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        text-align: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 20px 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 15px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          background: #f5f7fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          transform: translateY(-3px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .module-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            transform: scale(1.1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .module-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          width: 60px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          height: 60px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          margin: 0 auto 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          border-radius: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          justify-content: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: white; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 28px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .module-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          margin-bottom: 5px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .module-desc { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 13px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 监控图表卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .monitor-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .chart-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        height: 300px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .mock-chart { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          height: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          justify-content: flex-end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .chart-bars { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            align-items: flex-end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            justify-content: space-around; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            gap: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            margin-bottom: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .bar { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              background: linear-gradient(to top, #409EFF, #66b1ff); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              border-radius: 4px 4px 0 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              min-height: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              animation: growBar 1s ease-out forwards; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              transform-origin: bottom; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                opacity: 0.8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              .bar-value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                top: -25px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                left: 50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                transform: translateX(-50%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                white-space: nowrap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .chart-labels { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            justify-content: space-around; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            padding-top: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            border-top: 1px solid #EBEEF5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 技术栈卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .tech-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .tech-tabs { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .tech-list { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .tech-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            padding: 8px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            border-bottom: 1px solid #f0f0f0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &:last-child { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              border-bottom: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .el-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              min-width: 120px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            .tech-version { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              font-size: 13px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 公告卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .notice-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      :deep(.el-timeline) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding-left: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .el-timeline-item__wrapper { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          padding-left: 28px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .el-timeline-item__timestamp { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 13px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .notice-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          h4 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            margin: 0 0 5px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 15px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-weight: 600; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            color: #303133; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          p { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            margin: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 13px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            line-height: 1.5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 快捷操作卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .quick-action-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .quick-actions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: grid; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grid-template-columns: repeat(2, 1fr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gap: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .el-button { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          height: 40px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          border-radius: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 响应式设计 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  @media (max-width: 768px) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .welcome-section { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      text-align: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      padding: 30px 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .welcome-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .welcome-title { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 28px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .welcome-subtitle { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          font-size: 16px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .welcome-illustration { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        width: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        max-width: 300px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        height: 200px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .stat-cards { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .stat-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 15px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .main-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .feature-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .module-item { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          padding: 15px 5px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .module-icon { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            width: 50px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            height: 50px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 24px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .module-name { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 14px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .module-desc { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .quick-action-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .quick-actions { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          grid-template-columns: 1fr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 动画效果 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@keyframes fadeInUp { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  from { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    opacity: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: translateY(20px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  to { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    opacity: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: translateY(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@keyframes pulse { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  0%, 100% { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: scale(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  50% { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: scale(1.1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@keyframes growBar { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  from { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: scaleY(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  to { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    transform: scaleY(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.stat-card, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.el-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  animation: fadeInUp 0.6s ease-out; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 延迟动画 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.stat-cards .el-col:nth-child(1) .stat-card { animation-delay: 0.1s; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.stat-cards .el-col:nth-child(2) .stat-card { animation-delay: 0.2s; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.stat-cards .el-col:nth-child(3) .stat-card { animation-delay: 0.3s; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.stat-cards .el-col:nth-child(4) .stat-card { animation-delay: 0.4s; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.notice-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .card-header { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .notice-badge { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      margin-left: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      :deep(.el-badge__content) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        height: 18px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        line-height: 18px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 0 6px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  :deep(.el-timeline) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .notice-content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      transition: all 0.3s; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        background: #f5f7fa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        border-radius: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin: -8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      h4 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gap: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .el-tag { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          margin-left: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .notice-meta { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-top: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        justify-content: space-between; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        align-items: center; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .notice-type { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          :deep(.el-tag) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            height: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            line-height: 18px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            padding: 0 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  :deep(.el-empty) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 20px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .el-empty__description { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      margin-top: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 公告详情弹窗样式 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+:global(.notice-detail-dialog) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .el-message-box__content { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    max-height: 60vh; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    overflow-y: auto; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 监控图表卡片 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.monitor-card { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .chart-container { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    height: 350px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    padding: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    .mock-chart { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      height: 100%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      flex-direction: column; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .chart-bars { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        align-items: flex-end; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        justify-content: space-around; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gap: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        .bar { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          background: linear-gradient(to top, #409EFF, #66b1ff); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          border-radius: 4px 4px 0 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          min-height: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          animation: growBar 1s ease-out forwards; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          transform-origin: bottom; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            opacity: 0.8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            transform: translateY(-2px); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .bar-value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            top: -25px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            left: 50%; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            transform: translateX(-50%); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            color: #606266; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            white-space: nowrap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .chart-lines { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        flex: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         position: relative; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        margin-bottom: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        background: #fafafa; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        border-radius: 4px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        overflow: hidden; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        svg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          display: block; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .grid { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            opacity: 0.5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        &::before { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          content: counter(list-item) '.'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          position: absolute; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          left: -20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          color: #409eff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          font-weight: bold; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .data-point { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            transition: all 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              r: 7; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              fill: #66b1ff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .value-label { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            opacity: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            transition: opacity 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &:hover .value-label { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            opacity: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .chart-labels { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        display: flex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        justify-content: space-around; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        color: #909399; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        padding-top: 10px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        border-top: 1px solid #EBEEF5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        span { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          cursor: pointer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          transition: color 0.3s ease; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &:hover { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            color: #409EFF; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// 添加折线动画 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@keyframes drawLine { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  to { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    stroke-dashoffset: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.chart-lines { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  polyline { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    stroke-dasharray: 1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    stroke-dashoffset: 1000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    animation: drawLine 2s ease-out forwards; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  .data-point { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    opacity: 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    animation: fadeIn 0.5s ease-out forwards; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @for $i from 1 through 7 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &:nth-child(#{$i}) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        animation-delay: #{$i * 0.1}s; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  .el-divider { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    background-color: #ddd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    margin: 30px 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@keyframes fadeIn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  to { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    opacity: 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </style> 
			 |