From c2f399f2c085a1ce803059c2e8c6399b6d077dd2 Mon Sep 17 00:00:00 2001
From: spring <2396852758@qq.com>
Date: 星期三, 13 八月 2025 17:55:34 +0800
Subject: [PATCH] 完成能源驾驶舱
---
src/views/energyManagement/energyCockpit/index.vue | 1380 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1,380 insertions(+), 0 deletions(-)
diff --git a/src/views/energyManagement/energyCockpit/index.vue b/src/views/energyManagement/energyCockpit/index.vue
new file mode 100644
index 0000000..9281e37
--- /dev/null
+++ b/src/views/energyManagement/energyCockpit/index.vue
@@ -0,0 +1,1380 @@
+<template>
+ <div class="app-container">
+ <!-- 椤甸潰鏍囬 -->
+ <div class="page-header">
+ <h2>鑳芥簮椹鹃┒鑸�</h2>
+ <div class="header-info">
+ <span class="update-time">鏈�鍚庢洿鏂帮細{{ lastUpdateTime }}</span>
+ <el-button type="primary" size="small" @click="refreshData">
+ <el-icon><Refresh /></el-icon>
+ 鍒锋柊鏁版嵁
+ </el-button>
+ </div>
+ </div>
+
+ <!-- 瀹炴椂鑳借�楃洃鎺� -->
+ <div class="real-time-monitor">
+ <el-row :gutter="20">
+ <el-col :span="8">
+ <el-card class="monitor-card">
+ <template #header>
+ <div class="card-header">
+ <span>鐢靛姏娑堣��</span>
+ <el-tag type="success" size="small">瀹炴椂</el-tag>
+ </div>
+ </template>
+ <div class="monitor-content">
+ <div class="monitor-value">
+ <span class="value">{{ electricityConsumption }}</span>
+ <span class="unit">kW路h</span>
+ </div>
+ <div class="monitor-trend">
+ <span class="trend-label">瓒嬪娍锛�</span>
+ <el-tag :type="getTrendType(electricityTrend)" size="small">
+ {{ electricityTrend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(electricityTrend) }}%
+ </el-tag>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="8">
+ <el-card class="monitor-card">
+ <template #header>
+ <div class="card-header">
+ <span>姘存秷鑰�</span>
+ <el-tag type="primary" size="small">瀹炴椂</el-tag>
+ </div>
+ </template>
+ <div class="monitor-content">
+ <div class="monitor-value">
+ <span class="value">{{ waterConsumption }}</span>
+ <span class="unit">m鲁</span>
+ </div>
+ <div class="monitor-trend">
+ <span class="trend-label">瓒嬪娍锛�</span>
+ <el-tag :type="getTrendType(waterTrend)" size="small">
+ {{ waterTrend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(waterTrend) }}%
+ </el-tag>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="8">
+ <el-card class="monitor-card">
+ <template #header>
+ <div class="card-header">
+ <span>姘斾綋娑堣��</span>
+ <el-tag type="warning" size="small">瀹炴椂</el-tag>
+ </div>
+ </template>
+ <div class="monitor-content">
+ <div class="monitor-value">
+ <span class="value">{{ gasConsumption }}</span>
+ <span class="unit">m鲁</span>
+ </div>
+ <div class="monitor-trend">
+ <span class="trend-label">瓒嬪娍锛�</span>
+ <el-tag :type="getTrendType(gasTrend)" size="small">
+ {{ gasTrend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(gasTrend) }}%
+ </el-tag>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 鑳借�楄秼鍔垮垎鏋� -->
+ <div class="trend-analysis">
+ <el-card>
+ <template #header>
+ <div class="card-header">
+ <span>鑳借�楄秼鍔垮垎鏋�</span>
+ <div class="time-selector">
+ <el-radio-group v-model="trendTimeUnit" @change="handleTrendTimeChange">
+ <el-radio value="hour">灏忔椂</el-radio>
+ <el-radio value="day">鏃�</el-radio>
+ <el-radio value="week">鍛�</el-radio>
+ <el-radio value="month">鏈�</el-radio>
+ <el-radio value="year">骞�</el-radio>
+ </el-radio-group>
+ </div>
+ </div>
+ </template>
+ <div class="chart-container">
+ <div ref="trendChart" style="width: 100%; height: 400px;"></div>
+ </div>
+ </el-card>
+ </div>
+
+ <!-- 鑳借�楃粺璁′笌鎺掑悕 -->
+ <div class="statistics-ranking">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-card class="statistics-card">
+ <template #header>
+ <div class="card-header">
+ <span class="card-title">鑳借�楃粺璁℃姤琛�</span>
+ <div class="header-actions">
+ <el-select v-model="statisticsPeriod" @change="handleStatisticsChange" size="small" style="width: 100px;">
+ <el-option label="鏃ョ粺璁�" value="day" />
+ <el-option label="鍛ㄧ粺璁�" value="week" />
+ <el-option label="鏈堢粺璁�" value="month" />
+ <el-option label="骞寸粺璁�" value="year" />
+ </el-select>
+ </div>
+ </div>
+ </template>
+ <div class="statistics-content">
+ <div class="statistics-item">
+ <span class="label">鎬昏兘鑰楋細</span>
+ <span class="value">{{ totalEnergyConsumption }} kW路h</span>
+ </div>
+ <div class="statistics-item">
+ <span class="label">鍚屾瘮锛�</span>
+ <span class="value" :class="getComparisonClass(yearOverYear)">
+ {{ yearOverYear > 0 ? '+' : '' }}{{ yearOverYear }}%
+ </span>
+ </div>
+ <div class="statistics-item">
+ <span class="label">鐜瘮锛�</span>
+ <span class="value" :class="getComparisonClass(monthOverMonth)">
+ {{ monthOverMonth > 0 ? '+' : '' }}{{ monthOverMonth }}%
+ </span>
+ </div>
+ <div class="statistics-item">
+ <span class="label">鑺傝兘鐜囷細</span>
+ <span class="value success">{{ energySavingRate }}%</span>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="12">
+ <el-card class="ranking-card">
+ <template #header>
+ <div class="card-header">
+ <span class="card-title">鑳借�楁帓鍚�</span>
+ <el-select v-model="rankingType" @change="handleRankingChange" size="small" style="width: 120px;">
+ <el-option label="閮ㄩ棬鎺掑悕" value="department" />
+ <el-option label="杞﹂棿鎺掑悕" value="workshop" />
+ <el-option label="璁惧鎺掑悕" value="equipment" />
+ </el-select>
+ </div>
+ </template>
+ <div class="ranking-list">
+ <div v-for="(item, index) in rankingList" :key="index" class="ranking-item">
+ <div class="ranking-number" :class="getRankingClass(index + 1)">{{ index + 1 }}</div>
+ <div class="ranking-info">
+ <div class="ranking-name">{{ item.name }}</div>
+ <div class="ranking-value">{{ item.value }} kW路h</div>
+ </div>
+ <div class="ranking-trend">
+ <el-tag :type="getTrendType(item.trend)" size="small">
+ {{ item.trend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(item.trend) }}%
+ </el-tag>
+ </div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 寮傚父鍒嗘瀽涓庢櫤鑳芥帶鍒� -->
+ <div class="analysis-control">
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-card class="abnormal-card">
+ <template #header>
+ <div class="card-header">
+ <span class="card-title">寮傚父鍒嗘瀽</span>
+ <el-tag type="danger" size="small">{{ abnormalCount }}涓紓甯�</el-tag>
+ </div>
+ </template>
+ <div class="abnormal-list">
+ <div v-for="(item, index) in abnormalList" :key="index" class="abnormal-item">
+ <div class="abnormal-icon">
+ <el-icon :color="getAbnormalColor(item.level)">
+ <Warning v-if="item.level === 'warning'" />
+ <CircleClose v-else />
+ </el-icon>
+ </div>
+ <div class="abnormal-content">
+ <div class="abnormal-title">{{ item.title }}</div>
+ <div class="abnormal-desc">{{ item.description }}</div>
+ <div class="abnormal-time">{{ item.time }}</div>
+ </div>
+ <div class="abnormal-action">
+ <el-button link size="small" @click="handleAbnormal(item)">澶勭悊</el-button>
+ </div>
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ <el-col :span="12">
+ <el-card class="control-card">
+ <template #header>
+ <div class="card-header">
+ <span class="card-title">鏅鸿兘鎺у埗绯荤粺</span>
+ <el-switch v-model="autoControlEnabled" @change="handleAutoControlChange" />
+ </div>
+ </template>
+ <div class="control-content">
+ <div class="control-item">
+ <span class="label">宄拌胺骞崇數浠风鐞嗭細</span>
+ <el-tag :type="getPriceType(currentPriceType)" size="small">
+ {{ getPriceTypeText(currentPriceType) }}
+ </el-tag>
+ </div>
+ <div class="control-item">
+ <span class="label">璐熻嵎棰勬祴锛�</span>
+ <span class="value">{{ loadForecast }} kW</span>
+ </div>
+ <div class="control-item">
+ <span class="label">鑷姩鍚仠锛�</span>
+ <el-tag :type="autoStartStop ? 'success' : 'info'" size="small">
+ {{ autoStartStop ? '宸插惎鐢�' : '宸茬鐢�' }}
+ </el-tag>
+ </div>
+ <div class="control-item">
+ <span class="label">鏅鸿兘璋冭妭锛�</span>
+ <el-progress :percentage="intelligentAdjustment" :color="getProgressColor" />
+ </div>
+ </div>
+ </el-card>
+ </el-col>
+ </el-row>
+ </div>
+
+ <!-- 鐜繚鎸囨爣 -->
+ <div class="environmental-indicators">
+ <el-card>
+ <template #header>
+ <div class="card-header">
+ <span>鐜繚鎸囨爣鐩戞帶</span>
+ </div>
+ </template>
+ <el-row :gutter="20">
+ <el-col :span="8">
+ <div class="indicator-item">
+ <div class="indicator-title">纰虫帓鏀鹃噺</div>
+ <div class="indicator-value">{{ carbonEmission }} kg</div>
+ <div class="indicator-trend">
+ <span>鍚屾瘮锛�</span>
+ <span :class="getComparisonClass(carbonEmissionTrend)">
+ {{ carbonEmissionTrend > 0 ? '+' : '' }}{{ carbonEmissionTrend }}%
+ </span>
+ </div>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="indicator-item">
+ <div class="indicator-title">鐜繚杈炬爣鐜�</div>
+ <div class="indicator-value">{{ environmentalCompliance }}%</div>
+ <div class="indicator-trend">
+ <span>鐩爣锛�</span>
+ <span class="success">95%</span>
+ </div>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="indicator-item">
+ <div class="indicator-title">缁胯壊鑳芥簮鍗犳瘮</div>
+ <div class="indicator-value">{{ greenEnergyRatio }}%</div>
+ <div class="indicator-trend">
+ <span>鐩爣锛�</span>
+ <span class="success">30%</span>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+ </el-card>
+ </div>
+
+ <!-- 澶氱淮搴︽姤琛� -->
+ <div class="multi-dimensional-reports">
+ <el-card>
+ <template #header>
+ <div class="card-header">
+ <span>澶氱淮搴︽姤琛�</span>
+ </div>
+ </template>
+ <div class="report-filters">
+ <el-row :gutter="20">
+ <el-col :span="6">
+ <el-form-item label="鏃堕棿缁村害">
+ <el-select v-model="reportTimeDimension" placeholder="閫夋嫨鏃堕棿缁村害">
+ <el-option label="灏忔椂" value="hour" />
+ <el-option label="鏃�" value="day" />
+ <el-option label="鍛�" value="week" />
+ <el-option label="鏈�" value="month" />
+ <el-option label="骞�" value="year" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="6">
+ <el-form-item label="閮ㄩ棬缁村害">
+ <el-select v-model="reportDepartmentDimension" placeholder="閫夋嫨閮ㄩ棬">
+ <el-option label="鍏ㄩ儴閮ㄩ棬" value="all" />
+ <el-option label="鐢熶骇閮�" value="production" />
+ <el-option label="鎶�鏈儴" value="technology" />
+ <el-option label="琛屾斂閮�" value="administration" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="6">
+ <el-form-item label="璁惧缁村害">
+ <el-select v-model="reportEquipmentDimension" placeholder="閫夋嫨璁惧绫诲瀷">
+ <el-option label="鍏ㄩ儴璁惧" value="all" />
+ <el-option label="鐢靛姏璁惧" value="electricity" />
+ <el-option label="姘村鐞嗚澶�" value="water" />
+ <el-option label="姘斾綋璁惧" value="gas" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <el-col :span="6">
+ <el-form-item>
+ <el-button type="primary" @click="generateReport">鐢熸垚鎶ヨ〃</el-button>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </div>
+ <div class="report-preview">
+ <div class="report-data">
+ <el-row :gutter="20">
+ <el-col :span="8">
+ <div class="data-card">
+ <div class="data-title">鐢靛姏娑堣��</div>
+ <div class="data-value">{{ reportData.electricity }} kW路h</div>
+ <div class="data-trend">
+ <span :class="getTrendClass(reportData.electricityTrend)">
+ {{ reportData.electricityTrend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(reportData.electricityTrend) }}%
+ </span>
+ </div>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="data-card">
+ <div class="data-title">姘存秷鑰�</div>
+ <div class="data-value">{{ reportData.water }} m鲁</div>
+ <div class="data-trend">
+ <span :class="getTrendClass(reportData.waterTrend)">
+ {{ reportData.waterTrend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(reportData.waterTrend) }}%
+ </span>
+ </div>
+ </div>
+ </el-col>
+ <el-col :span="8">
+ <div class="data-card">
+ <div class="data-title">姘斾綋娑堣��</div>
+ <div class="data-value">{{ reportData.gas }} m鲁</div>
+ <div class="data-trend">
+ <span :class="getTrendClass(reportData.gasTrend)">
+ {{ reportData.gasTrend > 0 ? '鈫�' : '鈫�' }} {{ Math.abs(reportData.gasTrend) }}%
+ </span>
+ </div>
+ </div>
+ </el-col>
+ </el-row>
+
+ <div class="report-chart">
+ <div class="chart-title">鑳借�楄秼鍔垮浘</div>
+ <div class="chart-bars">
+ <div v-for="(item, index) in reportData.chartData" :key="index" class="chart-bar">
+ <div class="bar-label">{{ item.label }}</div>
+ <div class="bar-container">
+ <div class="bar-fill" :style="{ height: item.percentage + '%', backgroundColor: item.color }"></div>
+ </div>
+ <div class="bar-value">{{ item.value }}</div>
+ </div>
+ </div>
+ </div>
+
+ <div class="report-summary">
+ <div class="summary-item">
+ <span class="summary-label">鎬昏兘鑰楋細</span>
+ <span class="summary-value">{{ reportData.totalEnergy }} kW路h</span>
+ </div>
+ <div class="summary-item">
+ <span class="summary-label">骞冲潎鑳借�楋細</span>
+ <span class="summary-value">{{ reportData.averageEnergy }} kW路h</span>
+ </div>
+ <div class="summary-item">
+ <span class="summary-label">鑳借�楁晥鐜囷細</span>
+ <span class="summary-value">{{ reportData.efficiency }}%</span>
+ </div>
+ </div>
+ </div>
+ </div>
+ </el-card>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
+import { ElMessage, ElMessageBox } from 'element-plus'
+import * as echarts from 'echarts'
+import {
+ Refresh,
+ Download,
+ Warning,
+ CircleClose,
+ Document,
+ Edit,
+ Bell
+} from '@element-plus/icons-vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const lastUpdateTime = ref('')
+const electricityConsumption = ref(0)
+const waterConsumption = ref(0)
+const gasConsumption = ref(0)
+const electricityTrend = ref(0)
+const waterTrend = ref(0)
+const gasTrend = ref(0)
+
+// 瓒嬪娍鍒嗘瀽
+const trendTimeUnit = ref('day')
+const trendChart = ref(null)
+let chartInstance = null
+
+// 缁熻鎶ヨ〃
+const statisticsPeriod = ref('month')
+const totalEnergyConsumption = ref(0)
+const yearOverYear = ref(0)
+const monthOverMonth = ref(0)
+const energySavingRate = ref(0)
+
+// 鑳借�楁帓鍚�
+const rankingType = ref('department')
+const rankingList = ref([])
+
+// 寮傚父鍒嗘瀽
+const abnormalCount = ref(0)
+const abnormalList = ref([])
+
+// 鏅鸿兘鎺у埗
+const autoControlEnabled = ref(true)
+const currentPriceType = ref('peak')
+const loadForecast = ref(0)
+const autoStartStop = ref(true)
+const intelligentAdjustment = ref(0)
+
+// 鐜繚鎸囨爣
+const carbonEmission = ref(0)
+const carbonEmissionTrend = ref(0)
+const environmentalCompliance = ref(0)
+const greenEnergyRatio = ref(0)
+
+// 澶氱淮搴︽姤琛�
+const reportTimeDimension = ref('month')
+const reportDepartmentDimension = ref('all')
+const reportEquipmentDimension = ref('all')
+const reportData = ref({
+ electricity: 0,
+ water: 0,
+ gas: 0,
+ electricityTrend: 0,
+ waterTrend: 0,
+ gasTrend: 0,
+ totalEnergy: 0,
+ averageEnergy: 0,
+ efficiency: 0,
+ chartData: []
+})
+
+// 瀹氭椂鍣�
+let updateTimer = null
+
+// 鑾峰彇瓒嬪娍绫诲瀷鏍峰紡
+const getTrendType = (trend) => {
+ if (trend > 0) return 'danger'
+ if (trend < 0) return 'success'
+ return 'info'
+}
+
+// 鑾峰彇瀵规瘮绫诲瀷鏍峰紡
+const getComparisonClass = (value) => {
+ if (value > 0) return 'danger'
+ if (value < 0) return 'success'
+ return 'info'
+}
+
+// 鑾峰彇鎺掑悕鏍峰紡
+const getRankingClass = (rank) => {
+ if (rank === 1) return 'ranking-first'
+ if (rank === 2) return 'ranking-second'
+ if (rank === 3) return 'ranking-third'
+ return 'ranking-normal'
+}
+
+// 鑾峰彇寮傚父棰滆壊
+const getAbnormalColor = (level) => {
+ return level === 'warning' ? '#E6A23C' : '#F56C6C'
+}
+
+// 鑾峰彇鐢典环绫诲瀷鏍峰紡
+const getPriceType = (type) => {
+ const typeMap = {
+ peak: 'danger',
+ normal: 'warning',
+ valley: 'success'
+ }
+ return typeMap[type] || 'info'
+}
+
+// 鑾峰彇鐢典环绫诲瀷鏂囨湰
+const getPriceTypeText = (type) => {
+ const typeMap = {
+ peak: '宄版椂',
+ normal: '骞虫椂',
+ valley: '璋锋椂'
+ }
+ return typeMap[type] || '鏈煡'
+}
+
+// 鑾峰彇杩涘害鏉¢鑹�
+const getProgressColor = (percentage) => {
+ if (percentage < 50) return '#67C23A'
+ if (percentage < 80) return '#E6A23C'
+ return '#F56C6C'
+}
+
+// 鑾峰彇瓒嬪娍鏍峰紡
+const getTrendClass = (trend) => {
+ if (trend > 0) return 'trend-up'
+ if (trend < 0) return 'trend-down'
+ return 'trend-stable'
+}
+
+// 妯℃嫙鏁版嵁鐢熸垚
+const generateMockData = () => {
+ // 瀹炴椂鑳借�楁暟鎹�
+ electricityConsumption.value = Math.floor(Math.random() * 1000) + 2000
+ waterConsumption.value = Math.floor(Math.random() * 100) + 150
+ gasConsumption.value = Math.floor(Math.random() * 50) + 80
+
+ // 瓒嬪娍鏁版嵁
+ electricityTrend.value = (Math.random() * 20 - 10).toFixed(1)
+ waterTrend.value = (Math.random() * 15 - 7.5).toFixed(1)
+ gasTrend.value = (Math.random() * 12 - 6).toFixed(1)
+
+ // 缁熻鏁版嵁
+ totalEnergyConsumption.value = Math.floor(Math.random() * 50000) + 100000
+ yearOverYear.value = (Math.random() * 20 - 10).toFixed(1)
+ monthOverMonth.value = (Math.random() * 15 - 7.5).toFixed(1)
+ energySavingRate.value = (Math.random() * 10 + 5).toFixed(1)
+
+ // 鎺掑悕鏁版嵁
+ rankingList.value = [
+ { name: '鐢熶骇杞﹂棿A', value: Math.floor(Math.random() * 5000) + 10000, trend: (Math.random() * 20 - 10).toFixed(1) },
+ { name: '鐢熶骇杞﹂棿B', value: Math.floor(Math.random() * 4000) + 8000, trend: (Math.random() * 20 - 10).toFixed(1) },
+ { name: '鎶�鏈爺鍙戦儴', value: Math.floor(Math.random() * 3000) + 6000, trend: (Math.random() * 20 - 10).toFixed(1) },
+ { name: '琛屾斂鍔炲叕鍖�', value: Math.floor(Math.random() * 2000) + 4000, trend: (Math.random() * 20 - 10).toFixed(1) },
+ { name: '鍚庡嫟淇濋殰鍖�', value: Math.floor(Math.random() * 1500) + 3000, trend: (Math.random() * 20 - 10).toFixed(1) }
+ ].sort((a, b) => b.value - a.value)
+
+ // 寮傚父鏁版嵁
+ abnormalCount.value = Math.floor(Math.random() * 5) + 1
+ abnormalList.value = [
+ { level: 'warning', title: '鐢靛姏璐熻嵎杩囬珮', description: '鐢熶骇杞﹂棿A鐢靛姏璐熻嵎杈惧埌85%锛屽缓璁鏌ヨ澶囪繍琛岀姸鎬�', time: '2鍒嗛挓鍓�' },
+ { level: 'error', title: '姘村帇寮傚父', description: '姘村鐞嗚澶囧帇鍔涘紓甯革紝褰撳墠鍘嬪姏0.3MPa锛屼綆浜庢甯歌寖鍥�', time: '5鍒嗛挓鍓�' }
+ ]
+
+ // 鏅鸿兘鎺у埗鏁版嵁
+ loadForecast.value = Math.floor(Math.random() * 500) + 1500
+ intelligentAdjustment.value = Math.floor(Math.random() * 30) + 60
+
+ // 鐜繚鎸囨爣
+ carbonEmission.value = Math.floor(Math.random() * 1000) + 5000
+ carbonEmissionTrend.value = (Math.random() * 15 - 7.5).toFixed(1)
+ environmentalCompliance.value = (Math.random() * 5 + 95).toFixed(1)
+ greenEnergyRatio.value = (Math.random() * 10 + 25).toFixed(1)
+
+ // 鏇存柊鏈�鍚庢洿鏂版椂闂�
+ lastUpdateTime.value = new Date().toLocaleString()
+
+ // 鍚屾椂鏇存柊鎶ヨ〃鏁版嵁
+ generateReportData()
+}
+
+// 鍒濆鍖栬秼鍔垮浘琛�
+const initTrendChart = () => {
+ if (chartInstance) {
+ chartInstance.dispose()
+ }
+
+ chartInstance = echarts.init(trendChart.value)
+
+ const option = {
+ title: {
+ text: '鑳借�楄秼鍔垮垎鏋�',
+ left: 'center'
+ },
+ tooltip: {
+ trigger: 'axis'
+ },
+ legend: {
+ data: ['鐢靛姏', '姘�', '姘斾綋'],
+ bottom: 10
+ },
+ xAxis: {
+ type: 'category',
+ data: generateTimeData()
+ },
+ yAxis: {
+ type: 'value',
+ name: '娑堣�楅噺'
+ },
+ series: [
+ {
+ name: '鐢靛姏',
+ type: 'line',
+ data: generateSeriesData(),
+ smooth: true
+ },
+ {
+ name: '姘�',
+ type: 'line',
+ data: generateSeriesData(),
+ smooth: true
+ },
+ {
+ name: '姘斾綋',
+ type: 'line',
+ data: generateSeriesData(),
+ smooth: true
+ }
+ ]
+ }
+
+ chartInstance.setOption(option)
+}
+
+// 鐢熸垚鏃堕棿鏁版嵁
+const generateTimeData = () => {
+ const data = []
+ const now = new Date()
+
+ switch (trendTimeUnit.value) {
+ case 'hour':
+ for (let i = 23; i >= 0; i--) {
+ const time = new Date(now.getTime() - i * 60 * 60 * 1000)
+ data.unshift(time.getHours() + ':00')
+ }
+ break
+ case 'day':
+ for (let i = 29; i >= 0; i--) {
+ const time = new Date(now.getTime() - i * 24 * 60 * 60 * 1000)
+ data.unshift(time.getDate() + '鏃�')
+ }
+ break
+ case 'week':
+ for (let i = 11; i >= 0; i--) {
+ data.unshift(`绗�${12 - i}鍛╜)
+ }
+ break
+ case 'month':
+ for (let i = 11; i >= 0; i--) {
+ const month = (12 - i) % 12 || 12
+ data.unshift(`${month}鏈坄)
+ }
+ break
+ case 'year':
+ for (let i = 4; i >= 0; i--) {
+ const year = new Date().getFullYear() - i
+ data.unshift(`${year}骞碻)
+ }
+ break
+ }
+
+ return data
+}
+
+// 鐢熸垚绯诲垪鏁版嵁
+const generateSeriesData = () => {
+ const data = []
+ const count = trendTimeUnit.value === 'hour' ? 24 :
+ trendTimeUnit.value === 'day' ? 30 :
+ trendTimeUnit.value === 'week' ? 12 :
+ trendTimeUnit.value === 'month' ? 12 : 5
+
+ for (let i = 0; i < count; i++) {
+ data.push(Math.floor(Math.random() * 1000) + 500)
+ }
+
+ return data
+}
+
+// 澶勭悊瓒嬪娍鏃堕棿鍙樺寲
+const handleTrendTimeChange = () => {
+ nextTick(() => {
+ initTrendChart()
+ })
+}
+
+// 澶勭悊缁熻鍛ㄦ湡鍙樺寲
+const handleStatisticsChange = () => {
+ generateMockData()
+}
+
+// 澶勭悊鎺掑悕绫诲瀷鍙樺寲
+const handleRankingChange = () => {
+ // 鏍规嵁绫诲瀷閲嶆柊鐢熸垚鎺掑悕鏁版嵁
+ generateMockData()
+}
+
+// 澶勭悊鑷姩鎺у埗鍙樺寲
+const handleAutoControlChange = (value) => {
+ ElMessage.success(`鏅鸿兘鎺у埗绯荤粺宸�${value ? '鍚敤' : '绂佺敤'}`)
+}
+
+// 澶勭悊寮傚父
+const handleAbnormal = (item) => {
+ ElMessage.info(`姝e湪澶勭悊寮傚父锛�${item.title}`)
+}
+
+// 鍒锋柊鏁版嵁
+const refreshData = () => {
+ generateMockData()
+ if (chartInstance) {
+ initTrendChart()
+ }
+ ElMessage.success('鏁版嵁宸插埛鏂�')
+}
+
+// 瀵煎嚭缁熻
+const exportStatistics = () => {
+ ElMessage.success('缁熻鏁版嵁瀵煎嚭鎴愬姛')
+}
+
+// 瀵煎嚭鐜繚鎶ュ憡
+const exportEnvironmentalReport = () => {
+ ElMessage.success('鐜繚鎶ュ憡瀵煎嚭鎴愬姛')
+}
+
+// 鐢熸垚鑷畾涔夋姤琛�
+const generateCustomReport = () => {
+ ElMessage.info('鑷畾涔夋姤琛ㄥ姛鑳藉紑鍙戜腑...')
+}
+
+// 璁㈤槄鎶ヨ〃
+const subscribeReport = () => {
+ ElMessage.info('鎶ヨ〃璁㈤槄鍔熻兘寮�鍙戜腑...')
+}
+
+// 鐢熸垚鎶ヨ〃鏁版嵁
+const generateReportData = () => {
+ // 鐢熸垚鍩虹鏁版嵁
+ reportData.value.electricity = Math.floor(Math.random() * 5000) + 8000
+ reportData.value.water = Math.floor(Math.random() * 200) + 300
+ reportData.value.gas = Math.floor(Math.random() * 100) + 150
+
+ // 鐢熸垚瓒嬪娍鏁版嵁
+ reportData.value.electricityTrend = (Math.random() * 20 - 10).toFixed(1)
+ reportData.value.waterTrend = (Math.random() * 15 - 7.5).toFixed(1)
+ reportData.value.gasTrend = (Math.random() * 12 - 6).toFixed(1)
+
+ // 璁$畻鎬昏兘鑰楀拰骞冲潎鑳借��
+ reportData.value.totalEnergy = reportData.value.electricity + reportData.value.water * 0.1 + reportData.value.gas * 0.05
+ reportData.value.averageEnergy = Math.floor(reportData.value.totalEnergy / 3)
+ reportData.value.efficiency = (Math.random() * 20 + 80).toFixed(1)
+
+ // 鐢熸垚鍥捐〃鏁版嵁
+ const labels = ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩']
+ const colors = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399', '#9c27b0', '#ff9800']
+
+ reportData.value.chartData = labels.map((label, index) => ({
+ label,
+ value: Math.floor(Math.random() * 1000) + 500,
+ percentage: Math.floor(Math.random() * 40) + 30,
+ color: colors[index]
+ }))
+}
+
+// 鐢熸垚鎶ヨ〃
+const generateReport = () => {
+ generateReportData()
+ ElMessage.success('鎶ヨ〃鐢熸垚鎴愬姛')
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// 鍚姩瀹氭椂鏇存柊
+const startAutoUpdate = () => {
+ updateTimer = setInterval(() => {
+ generateMockData()
+ if (chartInstance) {
+ initTrendChart()
+ }
+ }, 60000) // 姣忓垎閽熸洿鏂颁竴娆�
+}
+
+// 鍋滄瀹氭椂鏇存柊
+const stopAutoUpdate = () => {
+ if (updateTimer) {
+ clearInterval(updateTimer)
+ updateTimer = null
+ }
+}
+
+// 缁勪欢鎸傝浇
+onMounted(() => {
+ generateMockData()
+ nextTick(() => {
+ initTrendChart()
+ })
+ startAutoUpdate()
+})
+
+// 缁勪欢鍗歌浇
+onUnmounted(() => {
+ stopAutoUpdate()
+ if (chartInstance) {
+ chartInstance.dispose()
+ }
+})
+</script>
+
+<style lang="scss" scoped>
+.app-container {
+ padding: 12px;
+ background: #f5f5f5;
+ min-height: 100vh;
+}
+
+.page-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+ padding: 16px;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+
+ h2 {
+ margin: 0;
+ color: #303133;
+ font-size: 22px;
+ }
+
+ .header-info {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ .update-time {
+ color: #909399;
+ font-size: 14px;
+ }
+ }
+}
+
+.real-time-monitor {
+ margin-bottom: 12px;
+
+ .monitor-card {
+ .monitor-content {
+ text-align: center;
+ padding: 16px 0;
+
+ .monitor-value {
+ margin-bottom: 12px;
+
+ .value {
+ font-size: 28px;
+ font-weight: bold;
+ color: #409eff;
+ }
+
+ .unit {
+ font-size: 14px;
+ color: #909399;
+ margin-left: 4px;
+ }
+ }
+
+ .monitor-trend {
+ .trend-label {
+ font-size: 14px;
+ color: #606266;
+ margin-right: 6px;
+ }
+ }
+ }
+ }
+}
+
+.trend-analysis {
+ margin-bottom: 12px;
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .time-selector {
+ .el-radio-group {
+ .el-radio {
+ margin-right: 4px;
+ }
+ }
+ }
+ }
+
+ .chart-container {
+ padding: 16px 0;
+ }
+}
+
+.statistics-ranking {
+ margin-bottom: 12px;
+
+ .statistics-card, .ranking-card {
+ height: 100%;
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+ border-radius: 8px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+ }
+ }
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 16px;
+ border-bottom: 1px solid #f0f0f0;
+ background: #fafafa;
+
+ .card-title {
+ font-size: 15px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .header-actions {
+ display: flex;
+ gap: 8px;
+ align-items: center;
+ }
+ }
+
+ .statistics-content {
+ padding: 16px;
+
+ .statistics-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+ padding: 10px 12px;
+ background: #f8f9fa;
+ border-radius: 6px;
+ transition: background-color 0.3s ease;
+
+ &:hover {
+ background: #e9ecef;
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ color: #606266;
+ font-size: 14px;
+ font-weight: 500;
+ }
+
+ .value {
+ font-weight: bold;
+ font-size: 15px;
+
+ &.success {
+ color: #67c23a;
+ }
+ }
+ }
+ }
+
+ .ranking-list {
+ padding: 16px;
+
+ .ranking-item {
+ display: flex;
+ align-items: center;
+ padding: 12px;
+ margin-bottom: 6px;
+ background: #f8f9fa;
+ border-radius: 6px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background: #e9ecef;
+ transform: translateX(4px);
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .ranking-number {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+ font-size: 14px;
+ margin-right: 12px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+
+ &.ranking-first {
+ background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
+ color: #fff;
+ }
+
+ &.ranking-second {
+ background: linear-gradient(135deg, #c0c0c0 0%, #d4d4d4 100%);
+ color: #fff;
+ }
+
+ &.ranking-third {
+ background: linear-gradient(135deg, #cd7f32 0%, #daa520 100%);
+ color: #fff;
+ }
+
+ &.ranking-normal {
+ background: linear-gradient(135deg, #f5f5f5 0%, #e9ecef 100%);
+ color: #909399;
+ }
+ }
+
+ .ranking-info {
+ flex: 1;
+
+ .ranking-name {
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 4px;
+ font-size: 14px;
+ }
+
+ .ranking-value {
+ color: #606266;
+ font-size: 13px;
+ font-weight: 500;
+ }
+ }
+
+ .ranking-trend {
+ margin-left: 12px;
+ }
+ }
+ }
+}
+
+.analysis-control {
+ margin-bottom: 20px;
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .abnormal-list {
+ .abnormal-item {
+ display: flex;
+ align-items: flex-start;
+ padding: 15px 0;
+ border-bottom: 1px solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ .abnormal-icon {
+ margin-right: 15px;
+ margin-top: 2px;
+ }
+
+ .abnormal-content {
+ flex: 1;
+
+ .abnormal-title {
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 5px;
+ }
+
+ .abnormal-desc {
+ color: #606266;
+ font-size: 14px;
+ margin-bottom: 5px;
+ }
+
+ .abnormal-time {
+ color: #909399;
+ font-size: 12px;
+ }
+ }
+
+ .abnormal-action {
+ margin-left: 15px;
+ }
+ }
+ }
+
+ .control-content {
+ .control-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ color: #606266;
+ font-size: 14px;
+ }
+
+ .value {
+ font-weight: bold;
+ color: #303133;
+ }
+ }
+ }
+}
+
+.environmental-indicators {
+ margin-bottom: 20px;
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .header-actions {
+ display: flex;
+ gap: 10px;
+ }
+ }
+
+ .indicator-item {
+ text-align: center;
+ padding: 20px 0;
+
+ .indicator-title {
+ color: #606266;
+ font-size: 14px;
+ margin-bottom: 10px;
+ }
+
+ .indicator-value {
+ font-size: 24px;
+ font-weight: bold;
+ color: #409eff;
+ margin-bottom: 10px;
+ }
+
+ .indicator-trend {
+ font-size: 12px;
+ color: #909399;
+
+ .success {
+ color: #67c23a;
+ }
+ }
+ }
+}
+
+.multi-dimensional-reports {
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .header-actions {
+ display: flex;
+ gap: 10px;
+ }
+ }
+
+ .report-filters {
+ padding: 20px 0;
+ border-bottom: 1px solid #f0f0f0;
+ margin-bottom: 20px;
+ }
+
+ .report-preview {
+ .report-data {
+ padding: 20px 0;
+
+ .data-card {
+ text-align: center;
+ padding: 16px;
+ background: #f8f9fa;
+ border-radius: 8px;
+ margin-bottom: 16px;
+
+ .data-title {
+ color: #606266;
+ font-size: 14px;
+ margin-bottom: 8px;
+ }
+
+ .data-value {
+ font-size: 20px;
+ font-weight: bold;
+ color: #303133;
+ margin-bottom: 8px;
+ }
+
+ .data-trend {
+ font-size: 12px;
+
+ .trend-up {
+ color: #f56c6c;
+ }
+
+ .trend-down {
+ color: #67c23a;
+ }
+
+ .trend-stable {
+ color: #909399;
+ }
+ }
+ }
+
+ .report-chart {
+ margin: 20px 0;
+ padding: 20px;
+ background: #f8f9fa;
+ border-radius: 8px;
+
+ .chart-title {
+ text-align: center;
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ margin-bottom: 16px;
+ }
+
+ .chart-bars {
+ display: flex;
+ justify-content: space-around;
+ align-items: flex-end;
+ height: 120px;
+
+ .chart-bar {
+ text-align: center;
+ flex: 1;
+ margin: 0 8px;
+
+ .bar-label {
+ font-size: 12px;
+ color: #606266;
+ margin-bottom: 8px;
+ }
+
+ .bar-container {
+ height: 80px;
+ background: #e9ecef;
+ border-radius: 4px;
+ position: relative;
+ margin-bottom: 8px;
+ }
+
+ .bar-fill {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ border-radius: 4px;
+ transition: height 0.3s ease;
+ }
+
+ .bar-value {
+ font-size: 12px;
+ color: #303133;
+ font-weight: 500;
+ }
+ }
+ }
+ }
+
+ .report-summary {
+ display: flex;
+ justify-content: space-around;
+ padding: 20px;
+ background: #f8f9fa;
+ border-radius: 8px;
+
+ .summary-item {
+ text-align: center;
+
+ .summary-label {
+ display: block;
+ color: #606266;
+ font-size: 14px;
+ margin-bottom: 8px;
+ }
+
+ .summary-value {
+ font-size: 18px;
+ font-weight: bold;
+ color: #303133;
+ }
+ }
+ }
+ }
+ }
+}
+
+// 閫氱敤鏍峰紡
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.success {
+ color: #67c23a;
+}
+
+.danger {
+ color: #f56c6c;
+}
+
+.warning {
+ color: #e6a23c;
+}
+
+.info {
+ color: #909399;
+}
+</style>
--
Gitblit v1.9.3