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