<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(`正在处理异常:${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>
|