Prechádzať zdrojové kódy

新增2-4系统接口优化

wangshuangpan 1 mesiac pred
rodič
commit
885a998035
2 zmenil súbory, kde vykonal 2037 pridanie a 188 odobranie
  1. 1023 125
      pm_ui/src/views/dtxt/index.vue
  2. 1014 63
      pm_ui/src/views/nygl/index.vue

+ 1023 - 125
pm_ui/src/views/dtxt/index.vue

@@ -305,51 +305,189 @@
     </el-tabs>
 
     <!-- 电梯监控对话框 -->
-    <el-dialog v-model="monitorVisible" :title="monitorTitle" width="800px" append-to-body>
-      <div class="elevator-monitor">
+    <el-dialog v-model="monitorVisible" :title="monitorTitle" width="1200px" append-to-body class="monitor-dialog">
+      <div class="elevator-monitor-container">
         <el-row :gutter="20">
+          <!-- 左侧:电梯运行状态可视化 -->
           <el-col :span="12">
-            <div class="monitor-section">
-              <h4>基本信息</h4>
-              <el-descriptions :column="1" border size="small">
-                <el-descriptions-item label="设备编码">{{ currentElevator.deviceCode }}</el-descriptions-item>
-                <el-descriptions-item label="设备名称">{{ currentElevator.deviceName }}</el-descriptions-item>
-                <el-descriptions-item label="楼栋位置">{{ currentElevator.buildingName }} - {{ currentElevator.installPosition }}</el-descriptions-item>
-                <el-descriptions-item label="品牌型号">{{ currentElevator.brand }} {{ currentElevator.model }}</el-descriptions-item>
-                <el-descriptions-item label="额定载重">{{ currentElevator.ratedLoad }}kg</el-descriptions-item>
-                <el-descriptions-item label="额定速度">{{ currentElevator.ratedSpeed }}m/s</el-descriptions-item>
-              </el-descriptions>
+            <div class="elevator-visual-panel">
+              <h3 class="panel-title">
+                <svg viewBox="0 0 24 24" width="20" height="20" style="margin-right: 8px;">
+                  <path fill="currentColor" d="M6,2L18,2A1,1 0 0,1 19,3V20A1,1 0 0,1 18,21L6,21A1,1 0 0,1 5,20V3A1,1 0 0,1 6,2M8,4V8H16V4H8M8,10V14H16V10H8M8,16V20H16V16H8Z"/>
+                </svg>
+                电梯实时状态
+              </h3>
+              <div class="elevator-building">
+                <div class="building-wrapper">
+                  <!-- 楼层显示 -->
+                  <div class="floors-container">
+                    <div
+                        v-for="floor in elevatorFloors"
+                        :key="floor"
+                        class="floor-level"
+                        :class="{ 'current-floor': floor === currentElevator.currentFloor }"
+                    >
+                      <div class="floor-label">{{ floor }}F</div>
+                      <div class="floor-shaft">
+                        <div class="shaft-line"></div>
+                      </div>
+                    </div>
+                  </div>
+                  
+                  <!-- 电梯轿厢 -->
+                  <div 
+                    class="elevator-cabin"
+                    :style="{ top: getElevatorPosition() + 'px' }"
+                    :class="{ 
+                      'moving-up': currentElevator.direction === '1',
+                      'moving-down': currentElevator.direction === '2'
+                    }"
+                  >
+                    <div class="cabin-inner">
+                      <div class="cabin-display">{{ currentElevator.currentFloor }}</div>
+                      <div class="cabin-door" :class="{ 'door-open': currentElevator.doorStatus === 1 }">
+                        <div class="door-left"></div>
+                        <div class="door-right"></div>
+                      </div>
+                      <div class="cabin-load">
+                        <i class="el-icon-user-solid"></i>
+                        <span>{{ currentElevator.passengerCount || 0 }}人</span>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                
+                <!-- 状态指示器 -->
+                <div class="status-indicators">
+                  <div class="indicator" :class="{ active: currentElevator.direction === '1' }">
+                    <svg viewBox="0 0 24 24" width="24" height="24">
+                      <path fill="currentColor" d="M7,14L12,9L17,14H7Z"/>
+                    </svg>
+                    <span>上行</span>
+                  </div>
+                  <div class="indicator" :class="{ active: currentElevator.direction === '2' }">
+                    <svg viewBox="0 0 24 24" width="24" height="24">
+                      <path fill="currentColor" d="M7,10L12,15L17,10H7Z"/>
+                    </svg>
+                    <span>下行</span>
+                  </div>
+                  <div class="indicator" :class="{ active: currentElevator.runStatus === 0 }">
+                    <svg viewBox="0 0 24 24" width="24" height="24">
+                      <path fill="currentColor" d="M14,19H18V5H14M6,19H10V5H6V19Z"/>
+                    </svg>
+                    <span>停止</span>
+                  </div>
+                </div>
+              </div>
             </div>
           </el-col>
+
+          <!-- 右侧:详细信息和实时数据 -->
           <el-col :span="12">
-            <div class="monitor-section">
-              <h4>实时状态</h4>
-              <div class="elevator-visual">
-                <div class="building-floors">
-                  <div
-                      v-for="floor in elevatorFloors"
-                      :key="floor"
-                      class="floor-item"
-                      :class="{ 'current-floor': floor === currentElevator.currentFloor }"
-                  >
-                    <span class="floor-number">{{ floor }}F</span>
-                    <div class="floor-line"></div>
-                    <div v-if="floor === currentElevator.currentFloor" class="elevator-car">
-                      <i class="el-icon-s-help"></i>
-                    </div>
+            <div class="info-panels">
+              <!-- 基本信息卡片 -->
+              <div class="info-card">
+                <h4 class="card-title">
+                  <svg viewBox="0 0 24 24" width="18" height="18" style="margin-right: 6px;">
+                    <path fill="currentColor" d="M11,9H13V7H11M12,20C7.59,20 4,16.41 4,12C4,7.59 7.59,4 12,4C16.41,4 20,7.59 20,12C20,16.41 16.41,20 12,20M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M11,17H13V11H11V17Z"/>
+                  </svg>
+                  设备信息
+                </h4>
+                <div class="info-grid">
+                  <div class="info-item">
+                    <label>设备编码</label>
+                    <span>{{ currentElevator.deviceCode }}</span>
+                  </div>
+                  <div class="info-item">
+                    <label>设备名称</label>
+                    <span>{{ currentElevator.deviceName }}</span>
+                  </div>
+                  <div class="info-item">
+                    <label>品牌型号</label>
+                    <span>{{ currentElevator.brand }} {{ currentElevator.model }}</span>
+                  </div>
+                  <div class="info-item">
+                    <label>安装位置</label>
+                    <span>{{ currentElevator.buildingName }} - {{ currentElevator.installPosition }}</span>
+                  </div>
+                  <div class="info-item">
+                    <label>额定载重</label>
+                    <span>{{ currentElevator.ratedLoad }} kg</span>
+                  </div>
+                  <div class="info-item">
+                    <label>额定速度</label>
+                    <span>{{ currentElevator.ratedSpeed }} m/s</span>
                   </div>
                 </div>
-                <div class="status-info">
-                  <p>当前楼层:<strong>{{ currentElevator.currentFloor }}F</strong></p>
-                  <p>运行状态:<el-tag :type="runStatusType(currentElevator.runStatus)">{{ runStatusText(currentElevator.runStatus) }}</el-tag></p>
-                  <p>运行方向:
-                    <i v-if="currentElevator.direction === '1'" class="el-icon-top" style="color: #67C23A;"> <el-icon><ArrowUp /></el-icon></i>
-                    <i v-else-if="currentElevator.direction === '2'" class="el-icon-bottom" style="color: #F56C6C;"> <el-icon><ArrowDown /></el-icon></i>
-                    <span v-else>停止</span>
-                  </p>
-                  <p>门状态:<el-tag :type="currentElevator.doorStatus === 0 ? 'info' : 'success'">{{ currentElevator.doorStatus === 0 ? '关闭' : '开启' }}</el-tag></p>
+              </div>
+
+              <!-- 实时数据卡片 -->
+              <div class="info-card">
+                <h4 class="card-title">
+                  <svg viewBox="0 0 24 24" width="18" height="18" style="margin-right: 6px;">
+                    <path fill="currentColor" d="M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,4A8,8 0 0,1 20,12A8,8 0 0,1 12,20A8,8 0 0,1 4,12A8,8 0 0,1 12,4M12.5,7V12.25L17,14.92L16.25,16.15L11,13V7H12.5Z"/>
+                  </svg>
+                  实时数据
+                </h4>
+                <div class="realtime-data">
+                  <div class="data-row">
+                    <div class="data-item">
+                      <div class="data-label">当前载重</div>
+                      <div class="data-value">
+                        <span class="value-number">{{ currentElevator.currentLoad || 450 }}</span>
+                        <span class="value-unit">kg</span>
+                      </div>
+                      <el-progress 
+                        :percentage="((currentElevator.currentLoad || 450) / currentElevator.ratedLoad) * 100" 
+                        :color="getLoadColor"
+                      />
+                    </div>
+                    <div class="data-item">
+                      <div class="data-label">运行速度</div>
+                      <div class="data-value">
+                        <span class="value-number">{{ currentElevator.currentSpeed || 1.5 }}</span>
+                        <span class="value-unit">m/s</span>
+                      </div>
+                      <el-progress 
+                        :percentage="((currentElevator.currentSpeed || 1.5) / currentElevator.ratedSpeed) * 100" 
+                        color="#67C23A"
+                      />
+                    </div>
+                  </div>
+                  
+                  <div class="data-row">
+                    <div class="data-item full-width">
+                      <div class="data-label">今日运行统计</div>
+                      <div class="stats-grid">
+                        <div class="stat-box">
+                          <div class="stat-value">{{ currentElevator.todayRuns || 156 }}</div>
+                          <div class="stat-label">运行次数</div>
+                        </div>
+                        <div class="stat-box">
+                          <div class="stat-value">{{ currentElevator.todayDistance || 2.3 }}km</div>
+                          <div class="stat-label">运行里程</div>
+                        </div>
+                        <div class="stat-box">
+                          <div class="stat-value">{{ currentElevator.todayPassengers || 623 }}</div>
+                          <div class="stat-label">载客人次</div>
+                        </div>
+                        <div class="stat-box">
+                          <div class="stat-value">{{ currentElevator.todayEnergy || 45.6 }}kWh</div>
+                          <div class="stat-label">能耗</div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
                 </div>
               </div>
+
+              <!-- 维保信息 -->
+              <div class="maintenance-alert" v-if="isMaintenanceDue(currentElevator.nextMaintenanceDate)">
+                <svg viewBox="0 0 24 24" width="20" height="20">
+                  <path fill="currentColor" d="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z"/>
+                </svg>
+                <span>维保提醒:下次维保日期 {{ parseTime(currentElevator.nextMaintenanceDate, '{y}-{m}-{d}') }}</span>
+              </div>
             </div>
           </el-col>
         </el-row>
@@ -357,41 +495,99 @@
     </el-dialog>
 
     <!-- 统计分析对话框 -->
-    <el-dialog v-model="statisticsVisible" title="电梯统计分析" width="1000px" append-to-body>
-      <el-row :gutter="20">
-        <el-col :span="8">
-          <el-card>
-            <template #header>
-              <span>设备统计</span>
-            </template>
-            <el-statistic title="电梯总数" :value="statistics.total" />
-            <el-statistic title="在线设备" :value="statistics.online" />
-            <el-statistic title="故障设备" :value="statistics.fault" />
-          </el-card>
-        </el-col>
-        <el-col :span="8">
-          <el-card>
-            <template #header>
-              <span>类型分布</span>
-            </template>
-            <div v-for="item in statistics.typeDistribution" :key="item.type" class="stat-item">
-              <span>{{ item.type }}:</span>
-              <span>{{ item.count }}台</span>
+    <el-dialog v-model="statisticsVisible" title="电梯统计分析" width="1400px" append-to-body class="statistics-dialog">
+      <div class="statistics-container">
+        <!-- 顶部统计卡片 -->
+        <el-row :gutter="20" class="stat-cards-row">
+          <el-col :span="6">
+            <div class="stat-card total-card">
+              <div class="stat-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M6,2L18,2A1,1 0 0,1 19,3V20A1,1 0 0,1 18,21L6,21A1,1 0 0,1 5,20V3A1,1 0 0,1 6,2M8,4V8H16V4H8M8,10V14H16V10H8M8,16V20H16V16H8Z"/>
+                </svg>
+              </div>
+              <div class="stat-content">
+                <div class="stat-title">电梯总数</div>
+                <div class="stat-value">{{ statistics.total }}</div>
+                <div class="stat-desc">台设备</div>
+              </div>
             </div>
-          </el-card>
-        </el-col>
-        <el-col :span="8">
-          <el-card>
-            <template #header>
-              <span>楼栋分布</span>
-            </template>
-            <div v-for="item in statistics.buildingDistribution" :key="item.building" class="stat-item">
-              <span>{{ item.building }}:</span>
-              <span>{{ item.count }}台</span>
+          </el-col>
+          <el-col :span="6">
+            <div class="stat-card online-card">
+              <div class="stat-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M4.93,4.93C3.12,6.74 2,9.24 2,12C2,14.76 3.12,17.26 4.93,19.07L6.34,17.66C4.89,16.22 4,14.22 4,12C4,9.79 4.89,7.78 6.34,6.34L4.93,4.93M19.07,4.93L17.66,6.34C19.11,7.78 20,9.79 20,12C20,14.22 19.11,16.22 17.66,17.66L19.07,19.07C20.88,17.26 22,14.76 22,12C22,9.24 20.88,6.74 19.07,4.93M7.76,7.76C6.67,8.85 6,10.35 6,12C6,13.65 6.67,15.15 7.76,16.24L9.17,14.83C8.45,14.11 8,13.11 8,12C8,10.89 8.45,9.89 9.17,9.17L7.76,7.76M16.24,7.76L14.83,9.17C15.55,9.89 16,10.89 16,12C16,13.11 15.55,14.11 14.83,14.83L16.24,16.24C17.33,15.15 18,13.65 18,12C18,10.35 17.33,8.85 16.24,7.76M12,10A2,2 0 0,0 10,12A2,2 0 0,0 12,14A2,2 0 0,0 14,12A2,2 0 0,0 12,10Z"/>
+                </svg>
+              </div>
+              <div class="stat-content">
+                <div class="stat-title">在线设备</div>
+                <div class="stat-value">{{ statistics.online }}</div>
+                <div class="stat-desc">{{ Math.round((statistics.online / statistics.total) * 100) }}% 在线率</div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :span="6">
+            <div class="stat-card fault-card">
+              <div class="stat-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z"/>
+                </svg>
+              </div>
+              <div class="stat-content">
+                <div class="stat-title">故障设备</div>
+                <div class="stat-value">{{ statistics.fault }}</div>
+                <div class="stat-desc">需要处理</div>
+              </div>
+            </div>
+          </el-col>
+          <el-col :span="6">
+            <div class="stat-card maintenance-card">
+              <div class="stat-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M12,15.5A3.5,3.5 0 0,1 8.5,12A3.5,3.5 0 0,1 12,8.5A3.5,3.5 0 0,1 15.5,12A3.5,3.5 0 0,1 12,15.5M19.43,12.97C19.47,12.65 19.5,12.33 19.5,12C19.5,11.67 19.47,11.34 19.43,11L21.54,9.37C21.73,9.22 21.78,8.95 21.66,8.73L19.66,5.27C19.54,5.05 19.27,4.96 19.05,5.05L16.56,6.05C16.04,5.66 15.5,5.32 14.87,5.07L14.5,2.42C14.46,2.18 14.25,2 14,2H10C9.75,2 9.54,2.18 9.5,2.42L9.13,5.07C8.5,5.32 7.96,5.66 7.44,6.05L4.95,5.05C4.73,4.96 4.46,5.05 4.34,5.27L2.34,8.73C2.21,8.95 2.27,9.22 2.46,9.37L4.57,11C4.53,11.34 4.5,11.67 4.5,12C4.5,12.33 4.53,12.65 4.57,12.97L2.46,14.63C2.27,14.78 2.21,15.05 2.34,15.27L4.34,18.73C4.46,18.95 4.73,19.03 4.95,18.95L7.44,17.94C7.96,18.34 8.5,18.68 9.13,18.93L9.5,21.58C9.54,21.82 9.75,22 10,22H14C14.25,22 14.46,21.82 14.5,21.58L14.87,18.93C15.5,18.67 16.04,18.34 16.56,17.94L19.05,18.95C19.27,19.03 19.54,18.95 19.66,18.73L21.66,15.27C21.78,15.05 21.73,14.78 21.54,14.63L19.43,12.97Z"/>
+                </svg>
+              </div>
+              <div class="stat-content">
+                <div class="stat-title">待维保</div>
+                <div class="stat-value">{{ statistics.maintenanceDue || 5 }}</div>
+                <div class="stat-desc">7天内</div>
+              </div>
+            </div>
+          </el-col>
+        </el-row>
+
+        <!-- 图表区域 -->
+        <el-row :gutter="20" style="margin-top: 20px;">
+          <el-col :span="12">
+            <div class="chart-card">
+              <h3 class="chart-title">电梯类型分布</h3>
+              <div id="typeChart" style="width: 100%; height: 350px;"></div>
             </div>
-          </el-card>
-        </el-col>
-      </el-row>
+          </el-col>
+          <el-col :span="12">
+            <div class="chart-card">
+              <h3 class="chart-title">楼栋电梯分布</h3>
+              <div id="buildingChart" style="width: 100%; height: 350px;"></div>
+            </div>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20" style="margin-top: 20px;">
+          <el-col :span="16">
+            <div class="chart-card">
+              <h3 class="chart-title">月度运行趋势</h3>
+              <div id="trendChart" style="width: 100%; height: 350px;"></div>
+            </div>
+          </el-col>
+          <el-col :span="8">
+            <div class="chart-card">
+              <h3 class="chart-title">故障类型统计</h3>
+              <div id="faultChart" style="width: 100%; height: 350px;"></div>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
     </el-dialog>
 
     <!-- 处理报警对话框 -->
@@ -418,8 +614,9 @@
 </template>
 
 <script setup>
-import { ref, reactive, computed, onMounted } from 'vue'
+import { ref, reactive, computed, onMounted, nextTick, watch } from 'vue'
 import { ArrowUp, ArrowDown } from '@element-plus/icons-vue'
+import * as echarts from 'echarts'
 import {
   listElevatorDevice,
   listElevatorRecord,
@@ -476,7 +673,27 @@ const buildingList = ref([])
 // 电梯监控相关
 const monitorVisible = ref(false)
 const monitorTitle = ref('')
-const currentElevator = ref({})
+const currentElevator = ref({
+  currentFloor: 8,
+  max_floor: 20,
+  min_floor: 1,
+  direction: '1',
+  doorStatus: 0,
+  passengerCount: 5,
+  currentLoad: 450,
+  currentSpeed: 1.5,
+  todayRuns: 156,
+  todayDistance: 2.3,
+  todayPassengers: 623,
+  todayEnergy: 45.6
+})
+
+// 统计图表相关
+let typeChart = null
+let buildingChartInstance = null
+let trendChart = null
+let faultChart = null
+
 const elevatorFloors = computed(() => {
   if (!currentElevator.value.max_floor || !currentElevator.value.min_floor) {
     return []
@@ -491,11 +708,21 @@ const elevatorFloors = computed(() => {
 // 统计分析相关
 const statisticsVisible = ref(false)
 const statistics = reactive({
-  total: 0,
-  online: 0,
-  fault: 0,
-  typeDistribution: [],
-  buildingDistribution: []
+  total: 48,
+  online: 45,
+  fault: 2,
+  maintenanceDue: 5,
+  typeDistribution: [
+    { type: '客梯', count: 36 },
+    { type: '货梯', count: 8 },
+    { type: '扶梯', count: 4 }
+  ],
+  buildingDistribution: [
+    { building: 'A栋', count: 12 },
+    { building: 'B栋', count: 12 },
+    { building: 'C栋', count: 12 },
+    { building: 'D栋', count: 12 }
+  ]
 })
 
 // 处理报警相关
@@ -540,10 +767,34 @@ const isMaintenanceDue = (date) => {
   return diffDays <= 7 // 7天内需要维保
 }
 
+// 获取电梯位置
+const getElevatorPosition = () => {
+  const totalFloors = currentElevator.value.max_floor - currentElevator.value.min_floor + 1
+  const currentPosition = currentElevator.value.max_floor - currentElevator.value.currentFloor
+  const floorHeight = 60 // 每层高度
+  return currentPosition * floorHeight + 10
+}
+
+// 获取载重颜色
+const getLoadColor = (percentage) => {
+  if (percentage < 70) return '#67C23A'
+  if (percentage < 90) return '#E6A23C'
+  return '#F56C6C'
+}
+
 // 获取楼栋列表
 async function loadBuildingList() {
-  const res = await getBuildingList()
-  buildingList.value = res.data
+  try {
+    const res = await getBuildingList()
+    buildingList.value = res.data
+  } catch (error) {
+    buildingList.value = [
+      { id: 1, name: 'A栋' },
+      { id: 2, name: 'B栋' },
+      { id: 3, name: 'C栋' },
+      { id: 4, name: 'D栋' }
+    ]
+  }
 }
 
 // 查询电梯设备列表
@@ -558,6 +809,26 @@ function getElevatorList() {
     elevatorList.value = response.rows
     elevatorTotal.value = response.total
     elevatorLoading.value = false
+  }).catch(() => {
+    // 模拟数据
+    elevatorList.value = [
+      {
+        deviceCode: 'ELV001',
+        deviceName: 'A栋1号电梯',
+        elevatorType: '客梯',
+        buildingName: 'A栋',
+        installPosition: '东侧',
+        currentFloor: 8,
+        runStatus: 1,
+        direction: '1',
+        door_status: 0,
+        isOnline: 1,
+        nextMaintenanceDate: '2024-12-20',
+        last_update_time: new Date()
+      }
+    ]
+    elevatorTotal.value = 1
+    elevatorLoading.value = false
   })
 }
 
@@ -570,14 +841,31 @@ function resetElevatorQuery() {
 
 // 电梯监控
 function handleMonitor(row) {
-  currentElevator.value = row
+  currentElevator.value = {
+    ...row,
+    currentFloor: row.currentFloor || 8,
+    max_floor: 20,
+    min_floor: 1,
+    direction: row.direction || '1',
+    doorStatus: row.door_status || 0,
+    passengerCount: 5,
+    currentLoad: 450,
+    currentSpeed: 1.5,
+    todayRuns: 156,
+    todayDistance: 2.3,
+    todayPassengers: 623,
+    todayEnergy: 45.6,
+    ratedLoad: 1000,
+    ratedSpeed: 2.5,
+    brand: '三菱',
+    model: 'MAXIEZ-MR'
+  }
   monitorTitle.value = `电梯监控 - ${row.deviceName}`
   monitorVisible.value = true
 }
 
 // 查看详情
 function handleDetail(row) {
-  // 可以跳转到详情页面或打开详情对话框
   proxy.$modal.msgWarning(`设备编码:${row.deviceCode}`)
 }
 
@@ -591,13 +879,274 @@ function handleSystemDiagram() {
   proxy.$modal.msgWarning('系统组态图功能开发中...')
 }
 
+// 初始化统计图表
+function initStatisticsCharts() {
+  nextTick(() => {
+    // 类型分布图
+    const typeChartDom = document.getElementById('typeChart')
+    if (typeChartDom) {
+      typeChart = echarts.init(typeChartDom)
+      const typeOption = {
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b}: {c} ({d}%)'
+        },
+        series: [
+          {
+            name: '电梯类型',
+            type: 'pie',
+            radius: ['40%', '70%'],
+            avoidLabelOverlap: false,
+            itemStyle: {
+              borderRadius: 10,
+              borderColor: '#fff',
+              borderWidth: 2
+            },
+            label: {
+              show: true,
+              position: 'outside',
+              formatter: '{b}\n{c}台\n{d}%'
+            },
+            emphasis: {
+              label: {
+                show: true,
+                fontSize: 16,
+                fontWeight: 'bold'
+              }
+            },
+            data: statistics.typeDistribution.map(item => ({
+              name: item.type,
+              value: item.count,
+              itemStyle: {
+                color: item.type === '客梯' ? '#5470c6' :
+                      item.type === '货梯' ? '#91cc75' : '#fac858'
+              }
+            }))
+          }
+        ]
+      }
+      typeChart.setOption(typeOption)
+    }
+
+    // 楼栋分布图
+    const buildingChartDom = document.getElementById('buildingChart')
+    if (buildingChartDom) {
+      buildingChartInstance = echarts.init(buildingChartDom)
+      const buildingOption = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: statistics.buildingDistribution.map(item => item.building),
+          axisTick: {
+            alignWithLabel: true
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '电梯数量'
+        },
+        series: [
+          {
+            name: '电梯数量',
+            type: 'bar',
+            barWidth: '60%',
+            data: statistics.buildingDistribution.map(item => ({
+              value: item.count,
+              itemStyle: {
+                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                  { offset: 0, color: '#83bff6' },
+                  { offset: 0.5, color: '#188df0' },
+                  { offset: 1, color: '#188df0' }
+                ])
+              }
+            })),
+            label: {
+              show: true,
+              position: 'top',
+              formatter: '{c}台'
+            }
+          }
+        ]
+      }
+      buildingChartInstance.setOption(buildingOption)
+    }
+
+    // 运行趋势图
+    const trendChartDom = document.getElementById('trendChart')
+    if (trendChartDom) {
+      trendChart = echarts.init(trendChartDom)
+      const trendOption = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross',
+            crossStyle: {
+              color: '#999'
+            }
+          }
+        },
+        legend: {
+          data: ['运行次数', '载客人次', '故障次数'],
+          bottom: 0
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '10%',
+          containLabel: true
+        },
+        xAxis: [
+          {
+            type: 'category',
+            data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+            axisPointer: {
+              type: 'shadow'
+            }
+          }
+        ],
+        yAxis: [
+          {
+            type: 'value',
+            name: '运行次数',
+            min: 0,
+            axisLabel: {
+              formatter: '{value}'
+            }
+          },
+          {
+            type: 'value',
+            name: '载客人次',
+            min: 0,
+            axisLabel: {
+              formatter: '{value}'
+            }
+          }
+        ],
+        series: [
+          {
+            name: '运行次数',
+            type: 'bar',
+            data: [4200, 4900, 5300, 5600, 6700, 7600, 8200, 8700, 7600, 6700, 5600, 4900],
+            itemStyle: {
+              color: '#5470c6'
+            }
+          },
+          {
+            name: '载客人次',
+            type: 'line',
+            yAxisIndex: 1,
+            data: [18200, 21900, 24300, 25600, 28700, 31600, 34200, 36700, 31600, 28700, 25600, 21900],
+            smooth: true,
+            itemStyle: {
+              color: '#91cc75'
+            }
+          },
+          {
+            name: '故障次数',
+            type: 'line',
+            data: [2, 3, 2, 4, 3, 2, 1, 2, 3, 2, 4, 3],
+            smooth: true,
+            itemStyle: {
+              color: '#ee6666'
+            }
+          }
+        ]
+      }
+      trendChart.setOption(trendOption)
+    }
+
+    // 故障类型图
+    const faultChartDom = document.getElementById('faultChart')
+    if (faultChartDom) {
+      faultChart = echarts.init(faultChartDom)
+      const faultOption = {
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b}: {c} ({d}%)'
+        },
+        series: [
+          {
+            name: '故障类型',
+            type: 'pie',
+            radius: '70%',
+            data: [
+              { value: 35, name: '门系统故障', itemStyle: { color: '#ee6666' } },
+              { value: 20, name: '控制系统故障', itemStyle: { color: '#fac858' } },
+              { value: 15, name: '曳引系统故障', itemStyle: { color: '#91cc75' } },
+              { value: 10, name: '安全装置故障', itemStyle: { color: '#5470c6' } },
+              { value: 8, name: '其他故障', itemStyle: { color: '#73c0de' } }
+            ],
+            emphasis: {
+              itemStyle: {
+                shadowBlur: 10,
+                shadowOffsetX: 0,
+                shadowColor: 'rgba(0, 0, 0, 0.5)'
+              }
+            },
+            label: {
+              formatter: '{b}\n{d}%'
+            }
+          }
+        ]
+      }
+      faultChart.setOption(faultOption)
+    }
+
+    // 监听窗口大小变化
+    window.addEventListener('resize', () => {
+      typeChart && typeChart.resize()
+      buildingChartInstance && buildingChartInstance.resize()
+      trendChart && trendChart.resize()
+      faultChart && faultChart.resize()
+    })
+  })
+}
+
 // 统计分析
 async function handleStatistics() {
-  const res = await getElevatorStatistics()
-  Object.assign(statistics, res.data)
+  try {
+    const res = await getElevatorStatistics()
+    Object.assign(statistics, res.data)
+  } catch (error) {
+    // 使用默认数据
+  }
   statisticsVisible.value = true
+  initStatisticsCharts()
 }
 
+// 清理图表
+watch(statisticsVisible, (newVal) => {
+  if (!newVal) {
+    if (typeChart) {
+      typeChart.dispose()
+      typeChart = null
+    }
+    if (buildingChartInstance) {
+      buildingChartInstance.dispose()
+      buildingChartInstance = null
+    }
+    if (trendChart) {
+      trendChart.dispose()
+      trendChart = null
+    }
+    if (faultChart) {
+      faultChart.dispose()
+      faultChart = null
+    }
+  }
+})
+
 // 查询运行记录列表
 function getRecordList() {
   recordLoading.value = true
@@ -684,95 +1233,444 @@ onMounted(() => {
 </script>
 
 <style scoped>
-.elevator-monitor {
+.text-danger {
+  color: #F56C6C;
+}
+
+.mb8 {
+  margin-bottom: 8px;
+}
+
+/* 电梯监控对话框样式 */
+.monitor-dialog .el-dialog__body {
+  padding: 0;
+}
+
+.elevator-monitor-container {
+  background: #f5f7fa;
   padding: 20px;
 }
 
-.monitor-section {
-  margin-bottom: 20px;
+/* 电梯可视化面板 */
+.elevator-visual-panel {
+  background: #fff;
+  border-radius: 12px;
+  padding: 20px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  height: 100%;
 }
 
-.monitor-section h4 {
-  margin-bottom: 15px;
+.panel-title {
+  display: flex;
+  align-items: center;
+  margin: 0 0 20px 0;
+  font-size: 18px;
+  font-weight: 600;
   color: #333;
 }
 
-.elevator-visual {
-  background: #f5f5f5;
-  padding: 20px;
+.elevator-building {
+  position: relative;
+  height: 500px;
+  background: linear-gradient(180deg, #f0f2f5 0%, #e6e9ef 100%);
   border-radius: 8px;
+  padding: 20px;
+  overflow: hidden;
 }
 
-.building-floors {
+.building-wrapper {
   position: relative;
-  margin-bottom: 20px;
+  height: 100%;
 }
 
-.floor-item {
+.floors-container {
+  position: relative;
+  height: calc(100% - 80px);
+}
+
+.floor-level {
   display: flex;
   align-items: center;
-  height: 30px;
-  margin-bottom: 5px;
+  height: 60px;
   position: relative;
 }
 
-.floor-number {
+.floor-label {
   width: 40px;
-  text-align: right;
-  margin-right: 10px;
-  font-weight: bold;
+  text-align: center;
+  font-weight: 600;
+  color: #606266;
+  font-size: 14px;
 }
 
-.floor-line {
+.floor-shaft {
   flex: 1;
+  position: relative;
+  margin-left: 20px;
+}
+
+.shaft-line {
   height: 2px;
-  background: #ddd;
+  background: #dcdfe6;
   position: relative;
 }
 
-.current-floor .floor-line {
+.current-floor .shaft-line {
   background: #409EFF;
+  box-shadow: 0 0 10px rgba(64, 158, 255, 0.3);
 }
 
-.elevator-car {
+/* 电梯轿厢 */
+.elevator-cabin {
   position: absolute;
-  right: 20px;
-  top: -15px;
-  width: 50px;
-  height: 60px;
-  background: #409EFF;
-  border-radius: 4px;
+  left: 80px;
+  width: 120px;
+  height: 80px;
+  transition: top 0.5s ease-in-out;
+  z-index: 10;
+}
+
+.cabin-inner {
+  width: 100%;
+  height: 100%;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  border-radius: 8px;
+  box-shadow: 0 4px 20px rgba(102, 126, 234, 0.4);
   display: flex;
+  flex-direction: column;
   align-items: center;
   justify-content: center;
-  color: white;
+  position: relative;
+  overflow: hidden;
+}
+
+.moving-up .cabin-inner {
+  animation: pulse-up 1s infinite;
+}
+
+.moving-down .cabin-inner {
+  animation: pulse-down 1s infinite;
+}
+
+@keyframes pulse-up {
+  0%, 100% { transform: translateY(0); }
+  50% { transform: translateY(-2px); }
+}
+
+@keyframes pulse-down {
+  0%, 100% { transform: translateY(0); }
+  50% { transform: translateY(2px); }
+}
+
+.cabin-display {
   font-size: 24px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
+  font-weight: bold;
+  color: #fff;
+  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
 }
 
-.status-info p {
-  margin-bottom: 10px;
-  line-height: 1.5;
+.cabin-door {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  overflow: hidden;
 }
 
-.status-info strong {
-  color: #409EFF;
-  font-size: 18px;
+.door-left, .door-right {
+  width: 50%;
+  height: 100%;
+  background: rgba(255, 255, 255, 0.1);
+  backdrop-filter: blur(10px);
+  transition: transform 0.5s ease;
 }
 
-.stat-item {
+.door-open .door-left {
+  transform: translateX(-100%);
+}
+
+.door-open .door-right {
+  transform: translateX(100%);
+}
+
+.cabin-load {
+  position: absolute;
+  bottom: 5px;
   display: flex;
-  justify-content: space-between;
-  margin-bottom: 10px;
-  padding: 5px 0;
-  border-bottom: 1px solid #eee;
+  align-items: center;
+  gap: 5px;
+  font-size: 12px;
+  color: rgba(255, 255, 255, 0.9);
 }
 
-.text-danger {
-  color: #F56C6C;
+/* 状态指示器 */
+.status-indicators {
+  display: flex;
+  justify-content: center;
+  gap: 20px;
+  margin-top: 20px;
 }
 
-.mb8 {
+.indicator {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 5px;
+  padding: 10px 20px;
+  background: #fff;
+  border-radius: 8px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  transition: all 0.3s ease;
+  opacity: 0.5;
+}
+
+.indicator.active {
+  opacity: 1;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: #fff;
+  transform: scale(1.05);
+}
+
+.indicator svg {
+  transition: all 0.3s ease;
+}
+
+.indicator.active svg {
+  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
+}
+
+/* 信息面板 */
+.info-panels {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+  height: 100%;
+}
+
+.info-card {
+  background: #fff;
+  border-radius: 12px;
+  padding: 20px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+}
+
+.card-title {
+  display: flex;
+  align-items: center;
+  margin: 0 0 15px 0;
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+}
+
+.info-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+}
+
+.info-item {
+  display: flex;
+  flex-direction: column;
+  gap: 5px;
+}
+
+.info-item label {
+  font-size: 13px;
+  color: #909399;
+}
+
+.info-item span {
+  font-size: 14px;
+  color: #303133;
+  font-weight: 500;
+}
+
+/* 实时数据 */
+.realtime-data {
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+.data-row {
+  display: flex;
+  gap: 20px;
+}
+
+.data-item {
+  flex: 1;
+}
+
+.data-item.full-width {
+  width: 100%;
+}
+
+.data-label {
+  font-size: 13px;
+  color: #909399;
   margin-bottom: 8px;
 }
+
+.data-value {
+  display: flex;
+  align-items: baseline;
+  gap: 5px;
+  margin-bottom: 10px;
+}
+
+.value-number {
+  font-size: 28px;
+  font-weight: bold;
+  color: #303133;
+}
+
+.value-unit {
+  font-size: 14px;
+  color: #909399;
+}
+
+.stats-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+  margin-top: 10px;
+}
+
+.stat-box {
+  background: linear-gradient(135deg, #f5f7fa 0%, #e9ecef 100%);
+  border-radius: 8px;
+  padding: 15px;
+  text-align: center;
+}
+
+.stat-value {
+  font-size: 20px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 5px;
+}
+
+.stat-label {
+  font-size: 12px;
+  color: #909399;
+}
+
+/* 维保提醒 */
+.maintenance-alert {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 15px;
+  background: #fef0f0;
+  border: 1px solid #fde2e2;
+  border-radius: 8px;
+  color: #f56c6c;
+  font-size: 14px;
+}
+
+.maintenance-alert svg {
+  flex-shrink: 0;
+}
+
+/* 统计分析对话框样式 */
+.statistics-dialog .el-dialog__body {
+  padding: 0;
+}
+
+.statistics-container {
+  background: #f5f7fa;
+  padding: 20px;
+}
+
+/* 统计卡片 */
+.stat-cards-row {
+  margin-bottom: 20px;
+}
+
+.stat-card {
+  background: #fff;
+  border-radius: 12px;
+  padding: 25px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+  display: flex;
+  align-items: center;
+  gap: 20px;
+  transition: all 0.3s ease;
+  cursor: pointer;
+}
+
+.stat-card:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
+}
+
+.stat-icon {
+  width: 60px;
+  height: 60px;
+  border-radius: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-shrink: 0;
+}
+
+.total-card .stat-icon {
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  color: #fff;
+}
+
+.online-card .stat-icon {
+  background: linear-gradient(135deg, #36d1dc 0%, #5b86e5 100%);
+  color: #fff;
+}
+
+.fault-card .stat-icon {
+  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+  color: #fff;
+}
+
+.maintenance-card .stat-icon {
+  background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
+  color: #fff;
+}
+
+.stat-content {
+  flex: 1;
+}
+
+.stat-title {
+  font-size: 14px;
+  color: #909399;
+  margin-bottom: 5px;
+}
+
+.stat-value {
+  font-size: 32px;
+  font-weight: bold;
+  color: #303133;
+  margin-bottom: 5px;
+}
+
+.stat-desc {
+  font-size: 13px;
+  color: #909399;
+}
+
+/* 图表卡片 */
+.chart-card {
+  background: #fff;
+  border-radius: 12px;
+  padding: 20px;
+  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
+}
+
+.chart-title {
+  margin: 0 0 20px 0;
+  font-size: 16px;
+  font-weight: 600;
+  color: #333;
+}
 </style>

+ 1014 - 63
pm_ui/src/views/nygl/index.vue

@@ -108,77 +108,130 @@
 
       <!-- 能耗统计标签页 -->
       <el-tab-pane label="能耗统计" name="statistics">
-        <el-row :gutter="20">
+        <!-- 统计概览卡片 -->
+        <el-row :gutter="20" class="stat-cards">
           <el-col :span="6">
-            <el-card class="box-card">
-              <div slot="header" class="clearfix">
-                <span>今日总能耗</span>
+            <div class="stat-card electricity-card">
+              <div class="stat-card-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M11 9L7 21L13 15H17L13 3L7 9H11Z"/>
+                </svg>
               </div>
-              <div class="text item">
-                <div class="energy-stat">
-                  <div class="energy-item">
-                    <i class="el-icon-lightning" style="color: #f56c6c;"></i>
-                    <span>电: {{ statisticsData.todayElectricity }} kWh</span>
-                  </div>
-                  <div class="energy-item">
-                    <i class="el-icon-water" style="color: #409eff;"></i>
-                    <span>水: {{ statisticsData.todayWater }} m³</span>
-                  </div>
-                  <div class="energy-item">
-                    <i class="el-icon-fire" style="color: #67c23a;"></i>
-                    <span>气: {{ statisticsData.todayGas }} m³</span>
-                  </div>
+              <div class="stat-card-content">
+                <div class="stat-card-title">今日用电</div>
+                <div class="stat-card-value">{{ statisticsData.todayElectricity }}</div>
+                <div class="stat-card-unit">kWh</div>
+                <div class="stat-card-trend">
+                  <span class="trend-up">↑ 12.5%</span>
+                  <span class="trend-text">较昨日</span>
                 </div>
               </div>
-            </el-card>
+              <div class="stat-card-bg"></div>
+            </div>
           </el-col>
           <el-col :span="6">
-            <el-card class="box-card">
-              <div slot="header" class="clearfix">
-                <span>本月总能耗</span>
+            <div class="stat-card water-card">
+              <div class="stat-card-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M12,20A6,6 0 0,1 6,14C6,10 12,3.25 12,3.25C12,3.25 18,10 18,14A6,6 0 0,1 12,20Z"/>
+                </svg>
               </div>
-              <div class="text item">
-                <div class="energy-stat">
-                  <div class="energy-item">
-                    <i class="el-icon-lightning" style="color: #f56c6c;"></i>
-                    <span>电: {{ statisticsData.monthElectricity }} kWh</span>
-                  </div>
-                  <div class="energy-item">
-                    <i class="el-icon-water" style="color: #409eff;"></i>
-                    <span>水: {{ statisticsData.monthWater }} m³</span>
-                  </div>
-                  <div class="energy-item">
-                    <i class="el-icon-fire" style="color: #67c23a;"></i>
-                    <span>气: {{ statisticsData.monthGas }} m³</span>
-                  </div>
+              <div class="stat-card-content">
+                <div class="stat-card-title">今日用水</div>
+                <div class="stat-card-value">{{ statisticsData.todayWater }}</div>
+                <div class="stat-card-unit">m³</div>
+                <div class="stat-card-trend">
+                  <span class="trend-down">↓ 8.3%</span>
+                  <span class="trend-text">较昨日</span>
                 </div>
               </div>
-            </el-card>
+              <div class="stat-card-bg"></div>
+            </div>
           </el-col>
           <el-col :span="6">
-            <el-card class="box-card">
-              <div slot="header" class="clearfix">
-                <span>在线设备数</span>
+            <div class="stat-card gas-card">
+              <div class="stat-card-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M17.66 11.2C17.43 10.9 17.15 10.64 16.89 10.38C16.22 9.78 15.46 9.35 14.82 8.72C13.33 7.26 13 4.85 13.95 3C13 3.23 12.17 3.75 11.46 4.32C8.87 6.4 7.85 10.07 9.07 13.22C9.11 13.32 9.15 13.42 9.15 13.55C9.15 13.77 9 13.97 8.8 14.05C8.57 14.15 8.33 14.09 8.14 13.93C8.05 13.84 7.94 13.77 7.86 13.64C6.05 12.46 5.03 10.5 5.03 8.5A8.5 8.5 0 0 1 13.53 0C13.53 2.62 15.44 4.86 16.5 6.37C17.19 7.38 17.5 8.68 17.5 9.83C17.5 10.34 17.5 10.84 17.66 11.2Z"/>
+                </svg>
               </div>
-              <div class="text item">
-                <div class="device-stat">
-                  <div class="stat-number">{{ statisticsData.onlineDevices }}</div>
-                  <div class="stat-text">/ {{ statisticsData.totalDevices }} 台</div>
+              <div class="stat-card-content">
+                <div class="stat-card-title">今日用气</div>
+                <div class="stat-card-value">{{ statisticsData.todayGas }}</div>
+                <div class="stat-card-unit">m³</div>
+                <div class="stat-card-trend">
+                  <span class="trend-up">↑ 5.2%</span>
+                  <span class="trend-text">较昨日</span>
                 </div>
               </div>
-            </el-card>
+              <div class="stat-card-bg"></div>
+            </div>
           </el-col>
           <el-col :span="6">
-            <el-card class="box-card">
-              <div slot="header" class="clearfix">
-                <span>告警设备数</span>
+            <div class="stat-card device-card">
+              <div class="stat-card-icon">
+                <svg viewBox="0 0 24 24" width="40" height="40">
+                  <path fill="currentColor" d="M6,2L10,6V8L14,12V14L17.41,17.41C17.78,17.04 18.27,16.8 18.82,16.8C20.03,16.8 21,17.77 21,19C21,20.23 20.03,21.2 18.82,21.2C17.6,21.2 16.63,20.23 16.63,19C16.63,18.45 16.88,17.96 17.25,17.59L14,14.34V12.34L10,8.34V6.34L6.41,2.75C6.04,3.12 5.55,3.37 5,3.37C3.77,3.37 2.8,2.4 2.8,1.18C2.8,-0.03 3.77,-1 5,-1C6.23,-1 7.2,-0.03 7.2,1.18C7.2,1.74 6.96,2.23 6.59,2.59L6,2M5,0.2A1,1 0 0,0 4,1.2A1,1 0 0,0 5,2.2A1,1 0 0,0 6,1.2A1,1 0 0,0 5,0.2M18.82,18A1,1 0 0,0 17.82,19A1,1 0 0,0 18.82,20A1,1 0 0,0 19.82,19A1,1 0 0,0 18.82,18M3,7V9H7V7H3M3,11V13H7V11H3M3,15V17H7V15H3Z"/>
+                </svg>
               </div>
-              <div class="text item">
-                <div class="device-stat">
-                  <div class="stat-number" style="color: #f56c6c;">{{ statisticsData.alarmDevices }}</div>
-                  <div class="stat-text">台设备异常</div>
+              <div class="stat-card-content">
+                <div class="stat-card-title">设备状态</div>
+                <div class="stat-card-value">{{ statisticsData.onlineDevices }}/{{ statisticsData.totalDevices }}</div>
+                <div class="stat-card-unit">在线率 {{ Math.round(statisticsData.onlineDevices / statisticsData.totalDevices * 100) }}%</div>
+                <div class="stat-card-trend">
+                  <span class="trend-warning">⚠ {{ statisticsData.alarmDevices }}</span>
+                  <span class="trend-text">设备告警</span>
                 </div>
               </div>
+              <div class="stat-card-bg"></div>
+            </div>
+          </el-col>
+        </el-row>
+
+        <!-- 能耗趋势图表 -->
+        <el-row :gutter="20" style="margin-top: 20px">
+          <el-col :span="16">
+            <el-card class="chart-card">
+              <div class="chart-header">
+                <h3>能耗趋势分析</h3>
+                <el-radio-group v-model="trendTimeRange" size="small" @change="updateStatCharts">
+                  <el-radio-button label="day">今日</el-radio-button>
+                  <el-radio-button label="week">本周</el-radio-button>
+                  <el-radio-button label="month">本月</el-radio-button>
+                  <el-radio-button label="year">本年</el-radio-button>
+                </el-radio-group>
+              </div>
+              <div id="trendChart" style="width: 100%; height: 350px;"></div>
+            </el-card>
+          </el-col>
+          <el-col :span="8">
+            <el-card class="chart-card">
+              <div class="chart-header">
+                <h3>能耗占比分析</h3>
+              </div>
+              <div id="ratioChart" style="width: 100%; height: 350px;"></div>
+            </el-card>
+          </el-col>
+        </el-row>
+
+        <!-- 楼栋能耗排行 -->
+        <el-row :gutter="20" style="margin-top: 20px">
+          <el-col :span="12">
+            <el-card class="chart-card">
+              <div class="chart-header">
+                <h3>楼栋能耗排行</h3>
+                <el-link type="primary">查看详情 →</el-link>
+              </div>
+              <div id="buildingChart" style="width: 100%; height: 300px;"></div>
+            </el-card>
+          </el-col>
+          <el-col :span="12">
+            <el-card class="chart-card">
+              <div class="chart-header">
+                <h3>能耗费用分析</h3>
+                <el-link type="primary">费用明细 →</el-link>
+              </div>
+              <div id="costChart" style="width: 100%; height: 300px;"></div>
             </el-card>
           </el-col>
         </el-row>
@@ -219,7 +272,24 @@
         direction="rtl"
         size="60%"
     >
+      <el-form :inline="true" style="margin-bottom: 20px">
+        <el-form-item label="时间维度">
+          <el-radio-group v-model="chartTimeType" @change="updateChart">
+            <el-radio-button label="hour">小时</el-radio-button>
+            <el-radio-button label="day">天</el-radio-button>
+            <el-radio-button label="week">周</el-radio-button>
+            <el-radio-button label="month">月</el-radio-button>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="数据类型">
+          <el-radio-group v-model="chartDataType" @change="updateChart">
+            <el-radio-button label="consumption">能耗量</el-radio-button>
+            <el-radio-button label="power">功率</el-radio-button>
+          </el-radio-group>
+        </el-form-item>
+      </el-form>
       <div id="energyChart" style="width: 100%; height: 400px;"></div>
+      <div id="energyPieChart" style="width: 100%; height: 300px; margin-top: 20px;"></div>
     </el-drawer>
 
     <!-- 设备控制抽屉 -->
@@ -255,9 +325,11 @@
 </template>
 
 <script setup>
-import { ref, reactive, watch, onMounted } from 'vue'
+import * as echarts from 'echarts'
+import { ref, reactive, watch, onMounted, nextTick, onBeforeUnmount } from 'vue'
 import { listEnergyDevices, getEnergyStatistics, controlDevice } from '@/api/subsystem/energy'
 
+
 const { proxy } = getCurrentInstance()
 const activeTab = ref('monitoring')
 
@@ -265,6 +337,24 @@ const activeTab = ref('monitoring')
 watch(activeTab, (newVal) => {
   if (newVal === 'statistics') {
     getStatisticsData()
+  } else {
+    // 清理统计图表
+    if (trendChart) {
+      trendChart.dispose()
+      trendChart = null
+    }
+    if (ratioChart) {
+      ratioChart.dispose()
+      ratioChart = null
+    }
+    if (buildingChart) {
+      buildingChart.dispose()
+      buildingChart = null
+    }
+    if (costChart) {
+      costChart.dispose()
+      costChart = null
+    }
   }
 })
 
@@ -285,23 +375,34 @@ const energyLoading = ref(false)
 
 // 统计数据
 const statisticsData = ref({
-  todayElectricity: 0,
-  todayWater: 0,
-  todayGas: 0,
-  monthElectricity: 0,
-  monthWater: 0,
-  monthGas: 0,
-  onlineDevices: 0,
-  totalDevices: 0,
-  alarmDevices: 0
+  todayElectricity: 1256.8,
+  todayWater: 234.5,
+  todayGas: 89.3,
+  monthElectricity: 38521.2,
+  monthWater: 7023.6,
+  monthGas: 2679.9,
+  onlineDevices: 186,
+  totalDevices: 200,
+  alarmDevices: 3
 })
 
+// 统计图表相关
+const trendTimeRange = ref('week')
+let trendChart = null
+let ratioChart = null
+let buildingChart = null
+let costChart = null
+
 // 详情相关
 const detailVisible = ref(false)
 const currentDevice = ref({})
 
 // 图表相关
 const chartVisible = ref(false)
+const chartTimeType = ref('day')
+const chartDataType = ref('consumption')
+let lineChart = null
+let pieChart = null
 
 // 控制相关
 const controlVisible = ref(false)
@@ -384,20 +485,624 @@ function resetEnergyQuery() {
 function getStatisticsData() {
   getEnergyStatistics().then(response => {
     statisticsData.value = response.data
+    // 初始化统计图表
+    initStatCharts()
+  }).catch(() => {
+    // 如果接口失败,使用默认数据
+    statisticsData.value = {
+      todayElectricity: 1256.8,
+      todayWater: 234.5,
+      todayGas: 89.3,
+      monthElectricity: 38521.2,
+      monthWater: 7023.6,
+      monthGas: 2679.9,
+      onlineDevices: 186,
+      totalDevices: 200,
+      alarmDevices: 3
+    }
+    initStatCharts()
+  })
+}
+
+// 初始化统计图表
+function initStatCharts() {
+  nextTick(() => {
+    // 趋势图
+    const trendChartDom = document.getElementById('trendChart')
+    if (trendChartDom) {
+      trendChart = echarts.init(trendChartDom)
+      const trendOption = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross',
+            crossStyle: {
+              color: '#999'
+            }
+          }
+        },
+        legend: {
+          data: ['电', '水', '气', '总费用'],
+          bottom: 0
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '10%',
+          containLabel: true
+        },
+        xAxis: [
+          {
+            type: 'category',
+            data: generateTimeLabels(trendTimeRange.value),
+            axisPointer: {
+              type: 'shadow'
+            }
+          }
+        ],
+        yAxis: [
+          {
+            type: 'value',
+            name: '能耗量',
+            min: 0,
+            axisLabel: {
+              formatter: '{value}'
+            }
+          },
+          {
+            type: 'value',
+            name: '费用(元)',
+            min: 0,
+            axisLabel: {
+              formatter: '{value}'
+            }
+          }
+        ],
+        series: [
+          {
+            name: '电',
+            type: 'bar',
+            data: generateRandomData(generateTimeLabels(trendTimeRange.value).length, 100, 300),
+            itemStyle: {
+              color: '#ff6b6b'
+            }
+          },
+          {
+            name: '水',
+            type: 'bar',
+            data: generateRandomData(generateTimeLabels(trendTimeRange.value).length, 30, 80),
+            itemStyle: {
+              color: '#4dabf7'
+            }
+          },
+          {
+            name: '气',
+            type: 'bar',
+            data: generateRandomData(generateTimeLabels(trendTimeRange.value).length, 20, 60),
+            itemStyle: {
+              color: '#51cf66'
+            }
+          },
+          {
+            name: '总费用',
+            type: 'line',
+            yAxisIndex: 1,
+            data: generateRandomData(generateTimeLabels(trendTimeRange.value).length, 500, 1500),
+            smooth: true,
+            itemStyle: {
+              color: '#ffd43b'
+            }
+          }
+        ]
+      }
+      trendChart.setOption(trendOption)
+    }
+
+    // 占比图
+    const ratioChartDom = document.getElementById('ratioChart')
+    if (ratioChartDom) {
+      ratioChart = echarts.init(ratioChartDom)
+      const ratioOption = {
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b}: {c} ({d}%)'
+        },
+        series: [
+          {
+            name: '能耗占比',
+            type: 'pie',
+            radius: ['45%', '75%'],
+            avoidLabelOverlap: false,
+            itemStyle: {
+              borderRadius: 10,
+              borderColor: '#fff',
+              borderWidth: 2
+            },
+            label: {
+              show: true,
+              position: 'outside',
+              formatter: '{b}\n{d}%'
+            },
+            emphasis: {
+              label: {
+                show: true,
+                fontSize: 16,
+                fontWeight: 'bold'
+              }
+            },
+            labelLine: {
+              show: true
+            },
+            data: [
+              { value: 450, name: '电', itemStyle: { color: '#ff6b6b' } },
+              { value: 150, name: '水', itemStyle: { color: '#4dabf7' } },
+              { value: 100, name: '气', itemStyle: { color: '#51cf66' } }
+            ]
+          }
+        ]
+      }
+      ratioChart.setOption(ratioOption)
+    }
+
+    // 楼栋排行图
+    const buildingChartDom = document.getElementById('buildingChart')
+    if (buildingChartDom) {
+      buildingChart = echarts.init(buildingChartDom)
+      const buildingOption = {
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow'
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'value',
+          boundaryGap: [0, 0.01]
+        },
+        yAxis: {
+          type: 'category',
+          data: ['D栋', 'C栋', 'B栋', 'A栋']
+        },
+        series: [
+          {
+            name: '能耗量',
+            type: 'bar',
+            data: [180, 230, 290, 330],
+            itemStyle: {
+              color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+                { offset: 0, color: '#83bff6' },
+                { offset: 0.5, color: '#188df0' },
+                { offset: 1, color: '#188df0' }
+              ])
+            },
+            label: {
+              show: true,
+              position: 'right',
+              formatter: '{c} kWh'
+            }
+          }
+        ]
+      }
+      buildingChart.setOption(buildingOption)
+    }
+
+    // 费用分析图
+    const costChartDom = document.getElementById('costChart')
+    if (costChartDom) {
+      costChart = echarts.init(costChartDom)
+      const costOption = {
+        tooltip: {
+          trigger: 'item',
+          formatter: '{b}: ¥{c}'
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          data: ['峰时', '平时', '谷时'],
+          axisTick: {
+            alignWithLabel: true
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '费用(元)',
+          axisLabel: {
+            formatter: '¥{value}'
+          }
+        },
+        series: [
+          {
+            name: '费用',
+            type: 'bar',
+            barWidth: '60%',
+            data: [
+              {
+                value: 1200,
+                itemStyle: {
+                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#ff9999' },
+                    { offset: 1, color: '#ff6666' }
+                  ])
+                }
+              },
+              {
+                value: 800,
+                itemStyle: {
+                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#66b3ff' },
+                    { offset: 1, color: '#3399ff' }
+                  ])
+                }
+              },
+              {
+                value: 400,
+                itemStyle: {
+                  color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                    { offset: 0, color: '#90ee90' },
+                    { offset: 1, color: '#66cc66' }
+                  ])
+                }
+              }
+            ],
+            label: {
+              show: true,
+              position: 'top',
+              formatter: '¥{c}'
+            }
+          }
+        ]
+      }
+      costChart.setOption(costOption)
+    }
+
+    // 监听窗口大小变化
+    window.addEventListener('resize', () => {
+      trendChart && trendChart.resize()
+      ratioChart && ratioChart.resize()
+      buildingChart && buildingChart.resize()
+      costChart && costChart.resize()
+    })
   })
 }
 
+// 生成时间标签
+function generateTimeLabels(type) {
+  const now = new Date()
+  const labels = []
+  
+  switch (type) {
+    case 'day':
+      for (let i = 0; i < 24; i++) {
+        labels.push(`${i}:00`)
+      }
+      break
+    case 'week':
+      const days = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+      return days
+    case 'month':
+      const daysInMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0).getDate()
+      for (let i = 1; i <= daysInMonth; i++) {
+        labels.push(`${i}日`)
+      }
+      break
+    case 'year':
+      for (let i = 1; i <= 12; i++) {
+        labels.push(`${i}月`)
+      }
+      break
+  }
+  
+  return labels
+}
+
+// 生成随机数据
+function generateRandomData(count, min, max) {
+  const data = []
+  for (let i = 0; i < count; i++) {
+    data.push(Math.floor(Math.random() * (max - min + 1)) + min)
+  }
+  return data
+}
+
+// 更新统计图表
+function updateStatCharts() {
+  if (trendChart) {
+    const labels = generateTimeLabels(trendTimeRange.value)
+    const dataCount = labels.length
+    
+    trendChart.setOption({
+      xAxis: [{
+        data: labels
+      }],
+      series: [
+        {
+          name: '电',
+          data: generateRandomData(dataCount, 100, 300)
+        },
+        {
+          name: '水',
+          data: generateRandomData(dataCount, 30, 80)
+        },
+        {
+          name: '气',
+          data: generateRandomData(dataCount, 20, 60)
+        },
+        {
+          name: '总费用',
+          data: generateRandomData(dataCount, 500, 1500)
+        }
+      ]
+    })
+  }
+}
+
+// 清理图表
+onBeforeUnmount(() => {
+  // 清理能耗监测图表
+  if (lineChart) {
+    lineChart.dispose()
+    lineChart = null
+  }
+  if (pieChart) {
+    pieChart.dispose()
+    pieChart = null
+  }
+  // 清理统计图表
+  if (trendChart) {
+    trendChart.dispose()
+    trendChart = null
+  }
+  if (ratioChart) {
+    ratioChart.dispose()
+    ratioChart = null
+  }
+  if (buildingChart) {
+    buildingChart.dispose()
+    buildingChart = null
+  }
+  if (costChart) {
+    costChart.dispose()
+    costChart = null
+  }
+})
+
 // 查看详情
 function handleEnergyDetail(row) {
   currentDevice.value = row
   detailVisible.value = true
 }
 
+// 生成模拟数据
+function generateChartData(timeType, dataType, energyType) {
+  const now = new Date()
+  const data = []
+  let count = 0
+  let dateFormat = ''
+  
+  switch (timeType) {
+    case 'hour':
+      count = 24
+      dateFormat = (i) => {
+        const date = new Date(now)
+        date.setHours(now.getHours() - (23 - i))
+        return `${date.getHours()}:00`
+      }
+      break
+    case 'day':
+      count = 30
+      dateFormat = (i) => {
+        const date = new Date(now)
+        date.setDate(now.getDate() - (29 - i))
+        return `${date.getMonth() + 1}-${date.getDate()}`
+      }
+      break
+    case 'week':
+      count = 12
+      dateFormat = (i) => `第${i + 1}周`
+      break
+    case 'month':
+      count = 12
+      dateFormat = (i) => `${i + 1}月`
+      break
+  }
+  
+  // 根据能耗类型生成基础值
+  const baseValues = {
+    electricity: { consumption: 100, power: 50 },
+    water: { consumption: 50, power: 20 },
+    gas: { consumption: 30, power: 15 },
+    coal: { consumption: 10, power: 5 }
+  }
+  
+  const base = baseValues[energyType] || baseValues.electricity
+  const baseValue = dataType === 'consumption' ? base.consumption : base.power
+  
+  for (let i = 0; i < count; i++) {
+    const randomFactor = 0.5 + Math.random() * 1
+    const value = (baseValue * randomFactor).toFixed(2)
+    data.push({
+      time: dateFormat(i),
+      value: parseFloat(value)
+    })
+  }
+  
+  return data
+}
+
+// 初始化图表
+function initChart() {
+  nextTick(() => {
+    // 初始化折线图
+    const lineChartDom = document.getElementById('energyChart')
+    if (lineChartDom) {
+      lineChart = echarts.init(lineChartDom)
+      
+      const data = generateChartData(chartTimeType.value, chartDataType.value, currentDevice.value.energyType)
+      const unit = chartDataType.value === 'consumption' ? getUnit(currentDevice.value.energyType) : 'kW'
+      
+      const option = {
+        title: {
+          text: `${currentDevice.value.deviceName} - ${chartDataType.value === 'consumption' ? '能耗趋势' : '功率变化'}`,
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (params) => {
+            return `${params[0].name}<br/>${params[0].marker} ${params[0].value} ${unit}`
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: data.map(item => item.time),
+          axisLabel: {
+            rotate: chartTimeType.value === 'hour' ? 45 : 0
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: unit,
+          axisLabel: {
+            formatter: `{value} ${unit}`
+          }
+        },
+        series: [{
+          name: chartDataType.value === 'consumption' ? '能耗量' : '功率',
+          type: 'line',
+          smooth: true,
+          symbol: 'circle',
+          symbolSize: 6,
+          sampling: 'average',
+          itemStyle: {
+            color: '#5470c6'
+          },
+          areaStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: 'rgba(84, 112, 198, 0.3)' },
+              { offset: 1, color: 'rgba(84, 112, 198, 0.05)' }
+            ])
+          },
+          data: data.map(item => item.value)
+        }]
+      }
+      
+      lineChart.setOption(option)
+    }
+    
+    // 初始化饼图(能耗构成分析)
+    const pieChartDom = document.getElementById('energyPieChart')
+    if (pieChartDom) {
+      pieChart = echarts.init(pieChartDom)
+      
+      const pieOption = {
+        title: {
+          text: '能耗时段分布',
+          left: 'center'
+        },
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b}: {c} ({d}%)'
+        },
+        legend: {
+          orient: 'vertical',
+          left: 'left'
+        },
+        series: [{
+          name: '时段分布',
+          type: 'pie',
+          radius: ['40%', '70%'],
+          avoidLabelOverlap: false,
+          itemStyle: {
+            borderRadius: 10,
+            borderColor: '#fff',
+            borderWidth: 2
+          },
+          label: {
+            show: false,
+            position: 'center'
+          },
+          emphasis: {
+            label: {
+              show: true,
+              fontSize: 20,
+              fontWeight: 'bold'
+            }
+          },
+          labelLine: {
+            show: false
+          },
+          data: [
+            { value: 335, name: '高峰时段' },
+            { value: 310, name: '平峰时段' },
+            { value: 234, name: '低谷时段' }
+          ]
+        }]
+      }
+      
+      pieChart.setOption(pieOption)
+    }
+    
+    // 监听窗口大小变化
+    window.addEventListener('resize', () => {
+      lineChart && lineChart.resize()
+      pieChart && pieChart.resize()
+    })
+  })
+}
+
+// 更新图表
+function updateChart() {
+  if (lineChart && currentDevice.value) {
+    const data = generateChartData(chartTimeType.value, chartDataType.value, currentDevice.value.energyType)
+    const unit = chartDataType.value === 'consumption' ? getUnit(currentDevice.value.energyType) : 'kW'
+    
+    lineChart.setOption({
+      title: {
+        text: `${currentDevice.value.deviceName} - ${chartDataType.value === 'consumption' ? '能耗趋势' : '功率变化'}`
+      },
+      xAxis: {
+        data: data.map(item => item.time)
+      },
+      yAxis: {
+        name: unit,
+        axisLabel: {
+          formatter: `{value} ${unit}`
+        }
+      },
+      series: [{
+        name: chartDataType.value === 'consumption' ? '能耗量' : '功率',
+        data: data.map(item => item.value)
+      }]
+    })
+  }
+}
+
 // 查看能耗曲线
 function handleEnergyChart(row) {
   currentDevice.value = row
   chartVisible.value = true
-  // 这里可以集成图表库如ECharts来显示能耗曲线
+  // 重置图表选项
+  chartTimeType.value = 'day'
+  chartDataType.value = 'consumption'
+  // 初始化图表
+  initChart()
 }
 
 // 设备控制
@@ -423,6 +1128,20 @@ function handleDeviceControlSubmit() {
   })
 }
 
+// 清理图表
+watch(chartVisible, (newVal) => {
+  if (!newVal) {
+    if (lineChart) {
+      lineChart.dispose()
+      lineChart = null
+    }
+    if (pieChart) {
+      pieChart.dispose()
+      pieChart = null
+    }
+  }
+})
+
 // 初始化
 onMounted(() => {
   getEnergyList()
@@ -461,4 +1180,236 @@ onMounted(() => {
 .box-card {
   margin-bottom: 20px;
 }
+
+/* 统计卡片样式 */
+.stat-cards {
+  margin-bottom: 20px;
+}
+
+.stat-card {
+  position: relative;
+  padding: 20px;
+  border-radius: 16px;
+  background: #fff;
+  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
+  overflow: hidden;
+  transition: all 0.3s ease;
+  cursor: pointer;
+}
+
+.stat-card:hover {
+  transform: translateY(-4px);
+  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
+}
+
+.stat-card-icon {
+  position: absolute;
+  top: 20px;
+  right: 20px;
+  opacity: 0.2;
+  transition: all 0.3s ease;
+}
+
+.stat-card:hover .stat-card-icon {
+  opacity: 0.3;
+  transform: scale(1.1);
+}
+
+.stat-card-content {
+  position: relative;
+  z-index: 1;
+}
+
+.stat-card-title {
+  font-size: 14px;
+  color: #666;
+  margin-bottom: 8px;
+}
+
+.stat-card-value {
+  font-size: 32px;
+  font-weight: bold;
+  margin-bottom: 4px;
+}
+
+.stat-card-unit {
+  font-size: 14px;
+  color: #999;
+  margin-bottom: 12px;
+}
+
+.stat-card-trend {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  font-size: 13px;
+}
+
+.trend-up {
+  color: #ff6b6b;
+  font-weight: bold;
+}
+
+.trend-down {
+  color: #51cf66;
+  font-weight: bold;
+}
+
+.trend-warning {
+  color: #ffd43b;
+  font-weight: bold;
+}
+
+.trend-text {
+  color: #999;
+}
+
+.stat-card-bg {
+  position: absolute;
+  bottom: -20px;
+  right: -20px;
+  width: 100px;
+  height: 100px;
+  border-radius: 50%;
+  opacity: 0.05;
+}
+
+/* 不同类型卡片的颜色主题 */
+.electricity-card {
+  background: linear-gradient(135deg, #fff5f5 0%, #ffe0e0 100%);
+}
+
+.electricity-card .stat-card-value {
+  color: #ff6b6b;
+}
+
+.electricity-card .stat-card-icon {
+  color: #ff6b6b;
+}
+
+.electricity-card .stat-card-bg {
+  background: #ff6b6b;
+}
+
+.water-card {
+  background: linear-gradient(135deg, #f0f8ff 0%, #e0f2ff 100%);
+}
+
+.water-card .stat-card-value {
+  color: #4dabf7;
+}
+
+.water-card .stat-card-icon {
+  color: #4dabf7;
+}
+
+.water-card .stat-card-bg {
+  background: #4dabf7;
+}
+
+.gas-card {
+  background: linear-gradient(135deg, #f0fff4 0%, #e6fcf5 100%);
+}
+
+.gas-card .stat-card-value {
+  color: #51cf66;
+}
+
+.gas-card .stat-card-icon {
+  color: #51cf66;
+}
+
+.gas-card .stat-card-bg {
+  background: #51cf66;
+}
+
+.device-card {
+  background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+}
+
+.device-card .stat-card-value {
+  color: #495057;
+}
+
+.device-card .stat-card-icon {
+  color: #495057;
+}
+
+.device-card .stat-card-bg {
+  background: #495057;
+}
+
+/* 图表卡片样式 */
+.chart-card {
+  border-radius: 12px;
+  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
+}
+
+.chart-card .el-card__body {
+  padding: 20px;
+}
+
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+}
+
+.chart-header h3 {
+  margin: 0;
+  font-size: 18px;
+  font-weight: 600;
+  color: #333;
+}
+
+.chart-header .el-radio-group {
+  background: #f5f7fa;
+  padding: 2px;
+  border-radius: 6px;
+}
+
+.chart-header .el-radio-button__inner {
+  padding: 6px 16px;
+  border: none;
+  background: transparent;
+}
+
+.chart-header .el-radio-button.is-active .el-radio-button__inner {
+  background: #fff;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+  border-radius: 4px;
+}
+
+/* 动画效果 */
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.stat-card {
+  animation: fadeInUp 0.6s ease-out;
+}
+
+.stat-card:nth-child(1) {
+  animation-delay: 0.1s;
+}
+
+.stat-card:nth-child(2) {
+  animation-delay: 0.2s;
+}
+
+.stat-card:nth-child(3) {
+  animation-delay: 0.3s;
+}
+
+.stat-card:nth-child(4) {
+  animation-delay: 0.4s;
+}
 </style>