楼宇能效监测控制系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

2174 lines
69 KiB

<template>
<div class="water-energy-trend">
<!-- 时间选择器 -->
<div class="time-selector">
<div class="selector-label">时间段选择</div>
<div class="time-periods">
<div
v-for="(period, index) in timePeriods"
:key="index"
:class="['period-item', { active: activePeriod === index }]"
@click="handlePeriodChange(index)"
>
{{ period }}
</div>
</div>
<div class="date-range" v-if="activePeriod === 3">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
@change="handleDateChange"
class="custom-picker"
/>
</div>
</div>
<!-- 对比控制 -->
<div class="compare-control">
<el-checkbox v-model="enableCompare">开启对比模式</el-checkbox>
<div class="compare-range" v-if="enableCompare">
<span class="compare-label">对比时间段:</span>
<el-date-picker
v-model="compareRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
size="small"
/>
</div>
<el-checkbox v-model="showWarningMarkers" style="margin-left: 0.2rem;">显示预警标记</el-checkbox>
</div>
<!-- 核心指标卡片 -->
<div class="indicator-cards">
<div class="indicator-card">
<div class="card-icon" style="background: linear-gradient(135deg, #5470C6 0%, #91CAFC 100%);">
<span>总用电</span>
</div>
<div class="card-content">
<div class="card-value">{{ indicators.totalElectricity }}</div>
<div class="card-label">总用电量(kWh)</div>
<div class="card-change" :class="indicators.electricityChange <= 0 ? 'positive' : 'negative'">
<span v-if="indicators.electricityChange > 0">↑</span>
<span v-else>↓</span>
{{ Math.abs(indicators.electricityChange) }}%
</div>
</div>
</div>
<div class="indicator-card">
<div class="card-icon" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
<span>总供水</span>
</div>
<div class="card-content">
<div class="card-value">{{ indicators.totalWaterSupply }}</div>
<div class="card-label">总供水量(m³)</div>
<div class="card-change" :class="indicators.waterSupplyChange >= 0 ? 'positive' : 'negative'">
<span v-if="indicators.waterSupplyChange >= 0">↑</span>
<span v-else>↓</span>
{{ Math.abs(indicators.waterSupplyChange) }}%
</div>
</div>
</div>
<div class="indicator-card">
<div class="card-icon" style="background: linear-gradient(135deg, #91CC75 0%, #F5A623 100%);">
<span>节能率</span>
</div>
<div class="card-content">
<div class="card-value">{{ indicators.savingRate }}%</div>
<div class="card-label">综合节能率</div>
<div class="card-change" :class="indicators.savingRateChange >= 0 ? 'positive' : 'negative'">
<span v-if="indicators.savingRateChange >= 0">↑</span>
<span v-else>↓</span>
{{ Math.abs(indicators.savingRateChange) }}%
</div>
</div>
</div>
<div class="indicator-card">
<div class="card-icon" style="background: linear-gradient(135deg, #FAC858 0%, #F59E0B 100%);">
<span>吨水能耗</span>
</div>
<div class="card-content">
<div class="card-value">{{ indicators.unitWaterEnergy }}</div>
<div class="card-label">吨水能耗(kWh/m³)</div>
<div class="card-change" :class="indicators.unitWaterEnergyChange <= 0 ? 'positive' : 'negative'">
<span v-if="indicators.unitWaterEnergyChange > 0">↑</span>
<span v-else>↓</span>
{{ Math.abs(indicators.unitWaterEnergyChange) }}%
</div>
</div>
</div>
<div class="indicator-card">
<div class="card-icon" style="background: linear-gradient(135deg, #73C0DE 0%, #3BA272 100%);">
<span>节电金额</span>
</div>
<div class="card-content">
<div class="card-value">{{ indicators.savingMoney }}万元</div>
<div class="card-label">累计节电金额</div>
<div class="card-change" :class="indicators.savingMoneyChange >= 0 ? 'positive' : 'negative'">
<span v-if="indicators.savingMoneyChange >= 0">↑</span>
<span v-else>↓</span>
{{ Math.abs(indicators.savingMoneyChange) }}%
</div>
</div>
</div>
</div>
<!-- 水泵系统总用电量趋势图 -->
<div class="chart-container">
<div class="chart-header">
<div class="chart-title">
<span class="title-icon" style="background: #15e1fd;"></span>
<span>水泵系统总用电量趋势</span>
</div>
<div class="chart-legend">
<div class="legend-item">
<span class="legend-dot" style="background: #15e1fd;"></span>
<span>当前时段</span>
</div>
<div class="legend-item" v-if="enableCompare">
<span class="legend-dot" style="background: #91CC75;"></span>
<span>对比时段</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #EE6666;"></span>
<span>预警时段</span>
</div>
</div>
</div>
<div class="chart" ref="totalElectricityChartRef"></div>
</div>
<!-- 水泵系统总供水量趋势图 -->
<div class="chart-container">
<div class="chart-header">
<div class="chart-title">
<span class="title-icon" style="background: #4facfe;"></span>
<span>水泵系统总供水量趋势</span>
</div>
<div class="chart-legend">
<div class="legend-item">
<span class="legend-dot" style="background: #4facfe;"></span>
<span>当前时段</span>
</div>
<div class="legend-item" v-if="enableCompare">
<span class="legend-dot" style="background: #5470C6;"></span>
<span>对比时段</span>
</div>
</div>
</div>
<div class="chart" ref="totalWaterSupplyChartRef"></div>
</div>
<!-- 分区用电量趋势图 -->
<div class="chart-container">
<div class="chart-header">
<div class="chart-title">
<span class="title-icon" style="background: #FAC858;"></span>
<span>分区用电量趋势</span>
</div>
<div class="chart-legend">
<div class="legend-item">
<span class="legend-dot" style="background: #667eea;"></span>
<span>高区</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #f093fb;"></span>
<span>中区</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #4facfe;"></span>
<span>低区</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #fa709a;"></span>
<span>消防区</span>
</div>
</div>
</div>
<div class="chart" ref="zoneElectricityChartRef"></div>
</div>
<!-- 分区供水量趋势图 -->
<div class="chart-container">
<div class="chart-header">
<div class="chart-title">
<span class="title-icon" style="background: #91CC75;"></span>
<span>分区供水量趋势</span>
</div>
<div class="chart-legend">
<div class="legend-item">
<span class="legend-dot" style="background: #667eea;"></span>
<span>高区</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #f093fb;"></span>
<span>中区</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #4facfe;"></span>
<span>低区</span>
</div>
<div class="legend-item">
<span class="legend-dot" style="background: #fa709a;"></span>
<span>消防区</span>
</div>
</div>
</div>
<div class="chart" ref="zoneWaterSupplyChartRef"></div>
</div>
<!-- 吨水能耗对比图 -->
<div class="chart-container">
<div class="chart-header">
<div class="chart-title">
<span class="title-icon" style="background: #5470C6;"></span>
<span>吨水能耗对比</span>
</div>
<div class="chart-controls">
<el-select v-model="waterEnergyChartType" @change="updateWaterEnergyChart" size="small" class="custom-select" style="width: 1rem;">
<el-option label="柱状图" value="bar"></el-option>
<el-option label="折线图" value="line"></el-option>
</el-select>
</div>
</div>
<div class="chart" ref="waterEnergyChartRef"></div>
</div>
<!-- 节能效果对比分析 -->
<div class="compare-analysis">
<div class="analysis-header">
<div class="analysis-title">节能效果对比分析</div>
</div>
<div class="analysis-content" v-if="enableCompare">
<div class="analysis-item">
<div class="analysis-label">用电量变化</div>
<div class="analysis-value" :class="compareAnalysis.electricityDiff <= 0 ? 'up' : 'down'">
{{ compareAnalysis.electricityDiff > 0 ? '+' : '' }}{{ compareAnalysis.electricityDiff }}kWh
</div>
<div class="analysis-percentage" :class="compareAnalysis.electricityRate <= 0 ? 'up' : 'down'">
({{ compareAnalysis.electricityRate > 0 ? '+' : '' }}{{ compareAnalysis.electricityRate }}%)
</div>
</div>
<div class="analysis-item">
<div class="analysis-label">供水量变化</div>
<div class="analysis-value" :class="compareAnalysis.waterSupplyDiff >= 0 ? 'up' : 'down'">
{{ compareAnalysis.waterSupplyDiff > 0 ? '+' : '' }}{{ compareAnalysis.waterSupplyDiff }}m³
</div>
<div class="analysis-percentage" :class="compareAnalysis.waterSupplyRate >= 0 ? 'up' : 'down'">
({{ compareAnalysis.waterSupplyRate > 0 ? '+' : '' }}{{ compareAnalysis.waterSupplyRate }}%)
</div>
</div>
<div class="analysis-item">
<div class="analysis-label">节能率变化</div>
<div class="analysis-value" :class="compareAnalysis.savingRateDiff >= 0 ? 'up' : 'down'">
{{ compareAnalysis.savingRateDiff > 0 ? '+' : '' }}{{ compareAnalysis.savingRateDiff }}%
</div>
<div class="analysis-percentage" :class="compareAnalysis.savingRateRate >= 0 ? 'up' : 'down'">
({{ compareAnalysis.savingRateRate > 0 ? '+' : '' }}{{ compareAnalysis.savingRateRate }}%)
</div>
</div>
<div class="analysis-item">
<div class="analysis-label">节电金额变化</div>
<div class="analysis-value" :class="compareAnalysis.moneyDiff >= 0 ? 'up' : 'down'">
{{ compareAnalysis.moneyDiff > 0 ? '+' : '' }}{{ compareAnalysis.moneyDiff }}万元
</div>
<div class="analysis-percentage" :class="compareAnalysis.moneyRate >= 0 ? 'up' : 'down'">
({{ compareAnalysis.moneyRate > 0 ? '+' : '' }}{{ compareAnalysis.moneyRate }}%)
</div>
</div>
</div>
<div class="analysis-hint" v-else>
<svg class="hint-icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/>
<path d="M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z" fill="currentColor"/>
</svg>
<span>开启对比模式后可查看两个时间段的用电量、供水量及节能效果对比分析</span>
</div>
</div>
<!-- 能耗预警与关联分析 -->
<div class="warning-energy-analysis">
<div class="section-header">
<div class="section-title">能耗预警与关联分析</div>
<div class="section-actions">
<el-select v-model="warningFilter.level" placeholder="预警级别" clearable size="small" class="custom-select" style="width: 1.2rem;">
<el-option label="全部" value=""></el-option>
<el-option label="严重" value="critical"></el-option>
<el-option label="重要" value="major"></el-option>
<el-option label="一般" value="minor"></el-option>
</el-select>
</div>
</div>
<!-- 预警时间轴与能耗影响 -->
<div class="warning-timeline-chart">
<div class="timeline-header">
<div class="header-item">
<span class="label">预警次数</span>
<span class="value">{{ warningStats.total }}</span>
</div>
<div class="header-item">
<span class="label">用电损失</span>
<span class="value warning-impact">{{ warningStats.electricityLoss }}kWh</span>
</div>
<div class="header-item">
<span class="label">节能率下降</span>
<span class="value warning-impact">{{ warningStats.savingRateDrop }}%</span>
</div>
<div class="header-item">
<span class="label">影响时长</span>
<span class="value">{{ warningStats.impactDuration }}小时</span>
</div>
</div>
<div class="timeline-chart" ref="warningTimelineChartRef"></div>
</div>
<!-- 预警影响详情表格 -->
<div class="warning-impact-table">
<div class="table-header">
<div class="table-title">预警影响详情</div>
</div>
<div class="table-container">
<table class="impact-table">
<thead>
<tr>
<th>预警时间</th>
<th>预警级别</th>
<th>预警标题</th>
<th>区域</th>
<th>状态</th>
<th>用电影响</th>
<th>供水影响</th>
<th>节能率影响</th>
<th>影响时长</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="warning in filteredWarnings" :key="warning.id">
<td>{{ warning.warningTime }}</td>
<td>
<span class="level-badge" :class="warning.level">{{ getWarningLevelText(warning.level) }}</span>
</td>
<td class="title-cell">{{ warning.title }}</td>
<td>{{ warning.zoneName }}</td>
<td>
<span class="status-badge" :class="warning.status">{{ getWarningStatusText(warning.status) }}</span>
</td>
<td :class="warning.electricityImpact > 0 ? 'energy-loss' : 'energy-save'">
{{ warning.electricityImpact > 0 ? '+' : '' }}{{ warning.electricityImpact }}kWh
</td>
<td :class="warning.waterSupplyImpact >= 0 ? 'water-up' : 'water-down'">
{{ warning.waterSupplyImpact > 0 ? '+' : '' }}{{ warning.waterSupplyImpact }}m³
</td>
<td :class="warning.savingRateImpact < 0 ? 'saving-drop' : 'saving-rise'">
{{ warning.savingRateImpact > 0 ? '+' : '' }}{{ warning.savingRateImpact }}%
</td>
<td>{{ warning.impactDuration }}h</td>
<td>
<div class="action-buttons">
<el-button
size="small"
type="primary"
@click="viewWarningDetail(warning)"
class="action-btn"
>
详情
</el-button>
<el-button
v-if="warning.status === 'pending' || warning.status === 'processing'"
size="small"
type="success"
@click="handleWarningResolve(warning)"
class="action-btn"
>
处理
</el-button>
<el-dropdown @command="(cmd) => handleWarningCommand(cmd, warning)" class="action-dropdown">
<el-button size="small" class="action-btn">
更多
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" style="margin-left: 0.04rem; width: 0.1rem; height: 0.1rem;">
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z" fill="currentColor"/>
<path d="M688 464H336c-8.8 0-16 7.2-16 16v64c0 8.8 7.2 16 16 16h352c8.8 0 16-7.2 16-16v-64c0-8.8-7.2-16-16-16z" fill="currentColor"/>
</svg>
</el-button>
<template #dropdown>
<el-dropdown-menu class="custom-dropdown-menu">
<el-dropdown-item command="markResolved" v-if="warning.status !== 'resolved'">标记已处理</el-dropdown-item>
<el-dropdown-item command="close" v-if="warning.status !== 'resolved'">关闭预警</el-dropdown-item>
<el-dropdown-item command="reopen" v-if="warning.status === 'resolved'">重新打开</el-dropdown-item>
<el-dropdown-item command="export" divided>导出报告</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- 预警详情弹窗 -->
<el-dialog
v-model="warningDetailDialogVisible"
title="预警与能耗关联详情"
width="900px"
class="custom-dialog"
>
<div class="warning-detail-content" v-if="selectedWarning">
<div class="detail-section">
<div class="section-title">预警信息</div>
<div class="info-grid">
<div class="info-item">
<span class="item-label">预警ID:</span>
<span class="item-value">{{ selectedWarning.id }}</span>
</div>
<div class="info-item">
<span class="item-label">预警级别:</span>
<span class="item-value level-badge" :class="selectedWarning.level">{{ getWarningLevelText(selectedWarning.level) }}</span>
</div>
<div class="info-item">
<span class="item-label">区域名称:</span>
<span class="item-value">{{ selectedWarning.zoneName }}</span>
</div>
<div class="info-item">
<span class="item-label">预警时间:</span>
<span class="item-value">{{ selectedWarning.warningTime }}</span>
</div>
<div class="info-item full-width">
<span class="item-label">预警描述:</span>
<span class="item-value">{{ selectedWarning.description }}</span>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">能耗影响分析</div>
<div class="impact-cards">
<div class="impact-card">
<div class="card-label">用电增加</div>
<div class="card-value energy-impact">{{ selectedWarning.electricityImpact }}kWh</div>
<div class="card-desc">相比正常运行时段</div>
</div>
<div class="impact-card">
<div class="card-label">供水减少</div>
<div class="card-value water-impact">{{ selectedWarning.waterSupplyImpact }}m³</div>
<div class="card-desc">系统供水量减少</div>
</div>
<div class="impact-card">
<div class="card-label">节能率下降</div>
<div class="card-value saving-impact">{{ selectedWarning.savingRateImpact }}%</div>
<div class="card-desc">系统节能率降低</div>
</div>
<div class="impact-card">
<div class="card-label">经济损失</div>
<div class="card-value cost-impact">{{ selectedWarning.costImpact }}元</div>
<div class="card-desc">电费损失估算</div>
</div>
</div>
</div>
<div class="detail-section">
<div class="section-title">能耗与供水趋势对比</div>
<div class="energy-comparison-chart" ref="energyComparisonChartRef"></div>
</div>
</div>
<template #footer>
<el-button @click="warningDetailDialogVisible = false" class="custom-btn">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import * as echarts from "echarts";
export default {
name: "WaterEnergyConsumptionEfficiencyTrend",
data() {
return {
timePeriods: ["近七日", "近一月", "近三月", "自定义"],
activePeriod: 0,
dateRange: [],
compareRange: [],
enableCompare: false,
showWarningMarkers: true,
indicators: {
totalElectricity: 285600,
electricityChange: -8.5,
totalWaterSupply: 125000,
waterSupplyChange: 5.2,
savingRate: 25.8,
savingRateChange: 6.8,
unitWaterEnergy: 0.73,
unitWaterEnergyChange: -12.5,
savingMoney: 28.6,
savingMoneyChange: 9.3
},
compareAnalysis: {
electricityDiff: -26500,
electricityRate: -8.5,
waterSupplyDiff: 6200,
waterSupplyRate: 5.2,
savingRateDiff: 1.8,
savingRateRate: 7.5,
moneyDiff: 2.5,
moneyRate: 9.6
},
warningStats: {
total: 15,
electricityLoss: 3850,
savingRateDrop: -4.8,
impactDuration: 72
},
warningFilter: {
level: ""
},
warningList: [],
waterEnergyChartType: "bar",
totalElectricityChart: null,
totalWaterSupplyChart: null,
zoneElectricityChart: null,
zoneWaterSupplyChart: null,
waterEnergyChart: null,
warningTimelineChart: null,
energyComparisonChart: null,
warningDetailDialogVisible: false,
selectedWarning: null
};
},
computed: {
filteredWarnings() {
let warnings = [...this.warningList];
if (this.warningFilter.level) {
warnings = warnings.filter(w => w.level === this.warningFilter.level);
}
return warnings;
}
},
mounted() {
this.initTotalElectricityChart();
this.initTotalWaterSupplyChart();
this.initZoneElectricityChart();
this.initZoneWaterSupplyChart();
this.initWaterEnergyChart();
this.initWarningTimelineChart();
this.initWarningList();
window.addEventListener("resize", this.handleResize);
},
beforeDestroy() {
window.removeEventListener("resize", this.handleResize);
if (this.totalElectricityChart) this.totalElectricityChart.dispose();
if (this.totalWaterSupplyChart) this.totalWaterSupplyChart.dispose();
if (this.zoneElectricityChart) this.zoneElectricityChart.dispose();
if (this.zoneWaterSupplyChart) this.zoneWaterSupplyChart.dispose();
if (this.waterEnergyChart) this.waterEnergyChart.dispose();
if (this.warningTimelineChart) this.warningTimelineChart.dispose();
if (this.energyComparisonChart) this.energyComparisonChart.dispose();
},
watch: {
activePeriod() {
this.updateAllCharts();
},
enableCompare() {
this.updateAllCharts();
},
compareRange() {
if (this.enableCompare) {
this.updateAllCharts();
}
},
showWarningMarkers() {
this.updateAllCharts();
},
"warningFilter.level"() {
this.updateWarningTimelineChart();
}
},
methods: {
handlePeriodChange(index) {
this.activePeriod = index;
},
handleDateChange(value) {
this.updateAllCharts();
},
initTotalElectricityChart() {
this.totalElectricityChart = echarts.init(this.$refs.totalElectricityChartRef);
this.updateTotalElectricityChart();
},
updateTotalElectricityChart() {
const dataMap = {
0: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
current: [42000, 45000, 43000, 48000, 51000, 46000, 44000],
compare: [46000, 49000, 47000, 52000, 55000, 50000, 48000],
warningData: [0, 1, 0, 2, 1, 0, 0]
},
1: {
xData: ["1日", "5日", "10日", "15日", "20日", "25日", "30日"],
current: [410000, 450000, 430000, 480000, 510000, 460000, 440000],
compare: [450000, 490000, 470000, 520000, 550000, 500000, 480000],
warningData: [3, 5, 2, 8, 6, 4, 3]
},
2: {
xData: ["1月", "2月", "3月"],
current: [12500000, 13800000, 13200000],
compare: [13600000, 15000000, 14400000],
warningData: [45, 62, 38]
},
3: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
current: [42000, 45000, 43000, 48000, 51000, 46000, 44000],
compare: [46000, 49000, 47000, 52000, 55000, 50000, 48000],
warningData: [0, 1, 0, 2, 1, 0, 0]
}
};
const currentData = dataMap[this.activePeriod];
const series = [
{
name: "当前时段",
type: "line",
smooth: true,
data: currentData.current,
itemStyle: { color: "#15e1fd" },
lineStyle: { color: "#15e1fd", width: 3 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(21, 225, 253, 0.5)" },
{ offset: 1, color: "rgba(21, 225, 253, 0)" }
])
}
}
];
if (this.showWarningMarkers) {
const warningPoints = currentData.warningData.map((value, index) => {
if (value > 0) {
return {
name: currentData.xData[index],
value: value,
xAxis: index,
yAxis: this.activePeriod === 2 ? 14000000 : 50000,
itemStyle: { color: "#EE6666" }
};
}
return null;
}).filter(item => item !== null);
if (warningPoints.length > 0) {
series[0].markPoint = {
data: warningPoints,
symbol: "pin",
symbolSize: 30,
label: { show: true, color: "#ffffff", fontSize: 10, formatter: "预警" }
};
}
}
if (this.enableCompare) {
series.push({
name: "对比时段",
type: "line",
smooth: true,
data: currentData.compare,
itemStyle: { color: "#91CC75" },
lineStyle: { color: "#91CC75", width: 2, type: "dashed" }
});
}
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "cross" } },
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
xAxis: {
type: "category",
boundaryGap: false,
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "kWh",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: series
};
this.totalElectricityChart.setOption(option);
},
initTotalWaterSupplyChart() {
this.totalWaterSupplyChart = echarts.init(this.$refs.totalWaterSupplyChartRef);
this.updateTotalWaterSupplyChart();
},
updateTotalWaterSupplyChart() {
const dataMap = {
0: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
current: [18500, 19500, 18800, 21000, 22500, 20000, 19000],
compare: [17500, 18500, 17800, 20000, 21500, 19000, 18000]
},
1: {
xData: ["1日", "5日", "10日", "15日", "20日", "25日", "30日"],
current: [180000, 190000, 183000, 205000, 220000, 195000, 185000],
compare: [170000, 180000, 173000, 195000, 210000, 185000, 175000]
},
2: {
xData: ["1月", "2月", "3月"],
current: [5500000, 5800000, 5650000],
compare: [5200000, 5500000, 5350000]
},
3: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
current: [18500, 19500, 18800, 21000, 22500, 20000, 19000],
compare: [17500, 18500, 17800, 20000, 21500, 19000, 18000]
}
};
const currentData = dataMap[this.activePeriod];
const series = [
{
name: "当前时段",
type: "line",
smooth: true,
data: currentData.current,
itemStyle: { color: "#4facfe" },
lineStyle: { color: "#4facfe", width: 3 },
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(79, 172, 254, 0.5)" },
{ offset: 1, color: "rgba(79, 172, 254, 0)" }
])
}
}
];
if (this.enableCompare) {
series.push({
name: "对比时段",
type: "line",
smooth: true,
data: currentData.compare,
itemStyle: { color: "#5470C6" },
lineStyle: { color: "#5470C6", width: 2, type: "dashed" }
});
}
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "cross" } },
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
xAxis: {
type: "category",
boundaryGap: false,
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "m³",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: series
};
this.totalWaterSupplyChart.setOption(option);
},
initZoneElectricityChart() {
this.zoneElectricityChart = echarts.init(this.$refs.zoneElectricityChartRef);
this.updateZoneElectricityChart();
},
updateZoneElectricityChart() {
const dataMap = {
0: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
highZone: [12500, 13500, 12800, 14500, 15500, 13800, 13000],
middleZone: [9200, 9800, 9400, 10500, 11200, 10100, 9500],
lowZone: [18000, 19000, 18500, 20500, 22000, 19500, 18500],
fireZone: [2300, 2200, 2300, 2500, 2300, 2400, 2500]
},
1: {
xData: ["1日", "5日", "10日", "15日", "20日", "25日", "30日"],
highZone: [120000, 135000, 128000, 145000, 155000, 138000, 130000],
middleZone: [88000, 94000, 90000, 101000, 108000, 97000, 91000],
middleZone: [172000, 182000, 177000, 197000, 212000, 187000, 177000],
fireZone: [22000, 21000, 22000, 24000, 22000, 23000, 24000]
},
2: {
xData: ["1月", "2月", "3月"],
highZone: [3750000, 4200000, 4000000],
middleZone: [2750000, 2920000, 2820000],
lowZone: [5380000, 5700000, 5550000],
fireZone: [680000, 650000, 680000]
},
3: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
highZone: [12500, 13500, 12800, 14500, 15500, 13800, 13000],
middleZone: [9200, 9800, 9400, 10500, 11200, 10100, 9500],
lowZone: [18000, 19000, 18500, 20500, 22000, 19500, 18500],
fireZone: [2300, 2200, 2300, 2500, 2300, 2400, 2500]
}
};
const currentData = dataMap[this.activePeriod];
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
xAxis: {
type: "category",
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "kWh",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: [
{
name: "高区",
type: "bar",
stack: "zone",
data: currentData.highZone,
itemStyle: { color: "#667eea" }
},
{
name: "中区",
type: "bar",
stack: "zone",
data: currentData.middleZone,
itemStyle: { color: "#f093fb" }
},
{
name: "低区",
type: "bar",
stack: "zone",
data: currentData.lowZone,
itemStyle: { color: "#4facfe" }
},
{
name: "消防区",
type: "bar",
stack: "zone",
data: currentData.fireZone,
itemStyle: { color: "#fa709a" }
}
]
};
this.zoneElectricityChart.setOption(option);
},
initZoneWaterSupplyChart() {
this.zoneWaterSupplyChart = echarts.init(this.$refs.zoneWaterSupplyChartRef);
this.updateZoneWaterSupplyChart();
},
updateZoneWaterSupplyChart() {
const dataMap = {
0: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
highZone: [5500, 5800, 5600, 6300, 6800, 6100, 5700],
middleZone: [4100, 4300, 4200, 4700, 5100, 4600, 4300],
lowZone: [8000, 8500, 8200, 9200, 9800, 8800, 8200],
fireZone: [900, 900, 900, 1000, 900, 950, 1000]
},
1: {
xData: ["1日", "5日", "10日", "15日", "20日", "25日", "30日"],
highZone: [52000, 56000, 54000, 61000, 66000, 59000, 55000],
middleZone: [39000, 41000, 40000, 45000, 49000, 44000, 41000],
lowZone: [76000, 81000, 78000, 88000, 94000, 84000, 78000],
fireZone: [8500, 8500, 8500, 9500, 8500, 9000, 9500]
},
2: {
xData: ["1月", "2月", "3月"],
highZone: [1620000, 1820000, 1740000],
middleZone: [1210000, 1280000, 1230000],
lowZone: [2360000, 2520000, 2420000],
fireZone: [265000, 250000, 265000]
},
3: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
highZone: [5500, 5800, 5600, 6300, 6800, 6100, 5700],
middleZone: [4100, 4300, 4200, 4700, 5100, 4600, 4300],
lowZone: [8000, 8500, 8200, 9200, 9800, 8800, 8200],
fireZone: [900, 900, 900, 1000, 900, 950, 1000]
}
};
const currentData = dataMap[this.activePeriod];
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
xAxis: {
type: "category",
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "m³",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: [
{
name: "高区",
type: "line",
smooth: true,
data: currentData.highZone,
itemStyle: { color: "#667eea" },
lineStyle: { color: "#667eea", width: 2 }
},
{
name: "中区",
type: "line",
smooth: true,
data: currentData.middleZone,
itemStyle: { color: "#f093fb" },
lineStyle: { color: "#f093fb", width: 2 }
},
{
name: "低区",
type: "line",
smooth: true,
data: currentData.lowZone,
itemStyle: { color: "#4facfe" },
lineStyle: { color: "#4facfe", width: 2 }
},
{
name: "消防区",
type: "line",
smooth: true,
data: currentData.fireZone,
itemStyle: { color: "#fa709a" },
lineStyle: { color: "#fa709a", width: 2 }
}
]
};
this.zoneWaterSupplyChart.setOption(option);
},
initWaterEnergyChart() {
this.waterEnergyChart = echarts.init(this.$refs.waterEnergyChartRef);
this.updateWaterEnergyChart();
},
updateWaterEnergyChart() {
const dataMap = {
0: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
current: [0.72, 0.73, 0.71, 0.74, 0.75, 0.72, 0.73],
compare: [0.78, 0.79, 0.77, 0.80, 0.81, 0.78, 0.79]
},
1: {
xData: ["1日", "5日", "10日", "15日", "20日", "25日", "30日"],
current: [0.71, 0.72, 0.70, 0.73, 0.74, 0.71, 0.72],
compare: [0.76, 0.77, 0.75, 0.78, 0.79, 0.76, 0.77]
},
2: {
xData: ["1月", "2月", "3月"],
current: [0.73, 0.74, 0.73],
compare: [0.78, 0.79, 0.78]
},
3: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
current: [0.72, 0.73, 0.71, 0.74, 0.75, 0.72, 0.73],
compare: [0.78, 0.79, 0.77, 0.80, 0.81, 0.78, 0.79]
}
};
const currentData = dataMap[this.activePeriod];
if (this.waterEnergyChartType === "bar") {
const series = [
{
name: "当前时段",
type: "bar",
data: currentData.current,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#5470C6" },
{ offset: 1, color: "#3E5F8A" }
])
}
}
];
if (this.enableCompare) {
series.push({
name: "对比时段",
type: "bar",
data: currentData.compare,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "#91CC75" },
{ offset: 1, color: "#66BB6A" }
])
}
});
}
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
xAxis: {
type: "category",
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "kWh/m³",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: series
};
this.waterEnergyChart.setOption(option);
} else {
const series = [
{
name: "当前时段",
type: "line",
smooth: true,
data: currentData.current,
itemStyle: { color: "#5470C6" },
lineStyle: { color: "#5470C6", width: 3 }
}
];
if (this.enableCompare) {
series.push({
name: "对比时段",
type: "line",
smooth: true,
data: currentData.compare,
itemStyle: { color: "#91CC75" },
lineStyle: { color: "#91CC75", width: 2, type: "dashed" }
});
}
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "cross" } },
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true },
xAxis: {
type: "category",
boundaryGap: false,
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "kWh/m³",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: series
};
this.waterEnergyChart.setOption(option);
}
},
updateAllCharts() {
this.updateTotalElectricityChart();
this.updateTotalWaterSupplyChart();
this.updateZoneElectricityChart();
this.updateZoneWaterSupplyChart();
this.updateWaterEnergyChart();
this.updateWarningTimelineChart();
},
handleResize() {
if (this.totalElectricityChart) this.totalElectricityChart.resize();
if (this.totalWaterSupplyChart) this.totalWaterSupplyChart.resize();
if (this.zoneElectricityChart) this.zoneElectricityChart.resize();
if (this.zoneWaterSupplyChart) this.zoneWaterSupplyChart.resize();
if (this.waterEnergyChart) this.waterEnergyChart.resize();
if (this.warningTimelineChart) this.warningTimelineChart.resize();
if (this.energyComparisonChart) this.energyComparisonChart.resize();
},
initWarningList() {
this.warningList = [
{
id: "WRN202403050001",
level: "critical",
title: "高区水泵能耗超标",
description: "高区水泵系统能耗超出阈值28.56%",
zoneName: "高区供水",
warningTime: "2024-03-05 10:30:25",
status: "pending",
electricityImpact: 520,
waterSupplyImpact: -85,
savingRateImpact: -9.2,
impactDuration: 8,
costImpact: 624,
energyData: { before: [12500, 12200, 12400, 12300], after: [13200, 12900, 13100, 13000] }
},
{
id: "WRN202403050002",
level: "critical",
title: "中区水泵异常",
description: "中区水泵系统能耗超出阈值35.68%",
zoneName: "中区供水",
warningTime: "2024-03-05 09:15:42",
status: "processing",
electricityImpact: 680,
waterSupplyImpact: -120,
savingRateImpact: -11.5,
impactDuration: 6,
costImpact: 816,
energyData: { before: [9200, 9100, 9300, 9200], after: [9950, 9850, 10050, 9950] }
},
{
id: "WRN202403050003",
level: "major",
title: "低区水泵运行异常",
description: "低区水泵系统能耗超出阈值15.25%",
zoneName: "低区供水",
warningTime: "2024-03-05 08:45:18",
status: "pending",
electricityImpact: 380,
waterSupplyImpact: -65,
savingRateImpact: -7.8,
impactDuration: 5,
costImpact: 456,
energyData: { before: [18000, 17800, 17900, 17800], after: [18550, 18350, 18450, 18350] }
},
{
id: "WRN202403040004",
level: "major",
title: "消防区泵能耗异常",
description: "消防区水泵能耗超出时长超标12.35%",
zoneName: "消防供水",
warningTime: "2024-03-04 16:22:33",
status: "resolved",
electricityImpact: 220,
waterSupplyImpact: 0,
savingRateImpact: -5.5,
impactDuration: 4,
costImpact: 264,
energyData: { before: [2300, 2250, 2280, 2270], after: [2480, 2430, 2460, 2450] }
},
{
id: "WRN202403040005",
level: "minor",
title: "系统吨水能耗轻微超标",
description: "系统吨水能耗超出阈值6.80%",
zoneName: "全系统",
warningTime: "2024-03-04 14:10:22",
status: "resolved",
electricityImpact: 180,
waterSupplyImpact: -25,
savingRateImpact: -4.2,
impactDuration: 3,
costImpact: 216,
energyData: { before: [42000, 41500, 41800, 41700], after: [42300, 41800, 42100, 42000] }
}
];
},
getWarningLevelText(level) {
const map = { critical: "严重", major: "重要", minor: "一般" };
return map[level] || level;
},
getWarningStatusText(status) {
const map = { pending: "待处理", processing: "处理中", resolved: "已处理" };
return map[status] || status;
},
initWarningTimelineChart() {
this.warningTimelineChart = echarts.init(this.$refs.warningTimelineChartRef);
this.updateWarningTimelineChart();
},
updateWarningTimelineChart() {
const dataMap = {
0: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
electricityData: [42000, 45000, 43000, 48000, 51000, 46000, 44000],
waterSupplyData: [18500, 19500, 18800, 21000, 22500, 20000, 19000],
savingRateData: [25.5, 26.2, 25.8, 24.5, 23.8, 25.0, 25.3],
warningData: [0, 1, 0, 2, 1, 0, 0]
},
1: {
xData: ["1日", "5日", "10日", "15日", "20日", "25日", "30日"],
electricityData: [410000, 450000, 430000, 480000, 510000, 460000, 440000],
waterSupplyData: [180000, 190000, 183000, 205000, 220000, 195000, 185000],
savingRateData: [25.0, 26.0, 25.5, 24.8, 24.0, 25.2, 25.5],
warningData: [3, 5, 2, 8, 6, 4, 3]
},
2: {
xData: ["1月", "2月", "3月"],
electricityData: [12500000, 13800000, 13200000],
waterSupplyData: [5500000, 5800000, 5650000],
savingRateData: [24.5, 26.0, 25.5],
warningData: [45, 62, 38]
},
3: {
xData: ["周一", "周二", "周三", "周四", "周五", "周六", "周日"],
electricityData: [42000, 45000, 43000, 48000, 51000, 46000, 44000],
waterSupplyData: [18500, 19500, 18800, 21000, 22500, 20000, 19000],
savingRateData: [25.5, 26.2, 25.8, 24.5, 23.8, 25.0, 25.3],
warningData: [0, 1, 0, 2, 1, 0, 0]
}
};
const currentData = dataMap[this.activePeriod];
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "cross" } },
legend: {
data: ["用电量", "供水量", "节能率", "预警次数"],
textStyle: { color: "rgba(255, 255, 255, 0.8)" },
top: 0
},
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true, top: "15%" },
xAxis: {
type: "category",
boundaryGap: false,
data: currentData.xData,
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: [
{
type: "value",
name: "用电量(kWh)",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
{
type: "value",
name: "供水量(m³)",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { show: false }
},
{
type: "value",
name: "节能率/预警数",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { show: false }
}
],
series: [
{
name: "用电量",
type: "line",
smooth: true,
data: currentData.electricityData,
itemStyle: { color: "#15e1fd" },
lineStyle: { color: "#15e1fd", width: 3 }
},
{
name: "供水量",
type: "line",
smooth: true,
yAxisIndex: 1,
data: currentData.waterSupplyData,
itemStyle: { color: "#4facfe" },
lineStyle: { color: "#4facfe", width: 2 }
},
{
name: "节能率",
type: "line",
smooth: true,
yAxisIndex: 2,
data: currentData.savingRateData,
itemStyle: { color: "#91CC75" },
lineStyle: { color: "#91CC75", width: 2 }
},
{
name: "预警次数",
type: "bar",
yAxisIndex: 2,
data: currentData.warningData,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: "rgba(238, 102, 102, 0.8)" },
{ offset: 1, color: "rgba(238, 102, 102, 0.3)" }
])
}
}
]
};
this.warningTimelineChart.setOption(option);
},
viewWarningDetail(warning) {
this.selectedWarning = warning;
this.warningDetailDialogVisible = true;
this.$nextTick(() => {
this.initEnergyComparisonChart();
});
},
handleWarningResolve(warning) {
warning.status = "processing";
this.$message.success("预警已开始处理");
},
handleWarningCommand(command, warning) {
if (command === "markResolved") {
warning.status = "resolved";
this.$message.success("已标记为已处理");
} else if (command === "close") {
warning.status = "resolved";
this.$message.success("预警已关闭");
} else if (command === "reopen") {
warning.status = "pending";
this.$message.success("预警已重新打开");
} else if (command === "export") {
this.$message.success("预警报告导出成功");
}
},
initEnergyComparisonChart() {
if (!this.$refs.energyComparisonChartRef || !this.selectedWarning) return;
this.energyComparisonChart = echarts.init(this.$refs.energyComparisonChartRef);
const { energyData } = this.selectedWarning;
const option = {
tooltip: { trigger: "axis", axisPointer: { type: "shadow" } },
legend: {
data: ["预警前", "预警后"],
textStyle: { color: "rgba(255, 255, 255, 0.8)" },
top: 0
},
grid: { left: "3%", right: "4%", bottom: "3%", containLabel: true, top: "10%" },
xAxis: {
type: "category",
data: ["时段1", "时段2", "时段3", "时段4", "时段5"],
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
axisTick: { show: false }
},
yAxis: {
type: "value",
name: "kWh",
nameTextStyle: { color: "rgba(255, 255, 255, 0.8)" },
axisLabel: { color: "rgba(255, 255, 255, 0.8)" },
axisLine: { lineStyle: { color: "#365576" } },
splitLine: { lineStyle: { color: "#1a3d62", type: "dashed" } }
},
series: [
{
name: "预警前",
type: "bar",
data: energyData.before,
itemStyle: { color: "#91CC75" }
},
{
name: "预警后",
type: "bar",
data: energyData.after,
itemStyle: { color: "#EE6666" }
}
]
};
this.energyComparisonChart.setOption(option);
}
}
};
</script>
<style lang="scss" scoped>
.water-energy-trend {
padding: 0.16rem;
}
.time-selector {
display: flex;
align-items: center;
gap: 0.2rem;
padding: 0.15rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 0.08rem;
margin-bottom: 0.16rem;
.selector-label {
font-size: 0.14rem;
color: #ffffff;
font-weight: bold;
}
.time-periods {
display: flex;
gap: 0.08rem;
.period-item {
padding: 0.06rem 0.15rem;
font-size: 0.13rem;
color: #ffffff;
opacity: 0.6;
cursor: pointer;
border-radius: 0.04rem;
transition: all 0.3s ease;
border: 1px solid transparent;
&:hover {
opacity: 0.9;
background: rgba(255, 255, 255, 0.1);
}
&.active {
opacity: 1;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-color: transparent;
}
}
}
.date-range {
::v-deep .custom-picker {
.el-input__wrapper {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
.el-input__inner {
color: #ffffff;
}
}
}
}
}
.compare-control {
display: flex;
align-items: center;
gap: 0.15rem;
padding: 0.15rem 0.2rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 0.08rem;
margin-bottom: 0.16rem;
.compare-range {
display: flex;
align-items: center;
gap: 0.1rem;
.compare-label {
font-size: 0.13rem;
color: #ffffff;
opacity: 0.7;
}
::v-deep .el-date-picker {
.el-input__wrapper {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
.el-input__inner {
color: #ffffff;
}
}
}
}
::v-deep .el-checkbox {
.el-checkbox__label {
color: #ffffff;
}
}
}
.indicator-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(2.5rem, 1fr));
gap: 0.15rem;
margin-bottom: 0.16rem;
.indicator-card {
display: flex;
align-items: center;
padding: 0.2rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 0.08rem;
transition: all 0.3s ease;
&:hover {
transform: translateY(-0.02rem);
box-shadow: 0 0.08rem 0.16rem rgba(0, 0, 0, 0.3);
}
.card-icon {
width: 0.6rem;
height: 0.6rem;
border-radius: 0.06rem;
display: flex;
align-items: center;
justify-content: center;
margin-right: 0.15rem;
color: #ffffff;
font-size: 0.18rem;
font-weight: bold;
}
.card-content {
flex: 1;
.card-value {
font-size: 0.24rem;
color: #15e1fd;
font-weight: bold;
margin-bottom: 0.05rem;
}
.card-label {
font-size: 0.12rem;
color: #ffffff;
opacity: 0.7;
margin-bottom: 0.05rem;
}
.card-change {
font-size: 0.12rem;
font-weight: 500;
&.positive {
color: #91CC75;
}
&.negative {
color: #EE6666;
}
}
}
}
}
.chart-container {
background: rgba(255, 255, 255, 0.03);
border-radius: 0.08rem;
padding: 0.2rem;
margin-bottom: 0.16rem;
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.2rem;
.chart-title {
font-size: 0.15rem;
color: #ffffff;
font-weight: bold;
display: flex;
align-items: center;
gap: 0.08rem;
.title-icon {
width: 0.04rem;
height: 0.16rem;
border-radius: 0.02rem;
}
}
.chart-legend {
display: flex;
gap: 0.15rem;
.legend-item {
display: flex;
align-items: center;
gap: 0.05rem;
font-size: 0.13rem;
color: #ffffff;
opacity: 0.7;
.legend-dot {
width: 0.1rem;
height: 0.1rem;
border-radius: 50%;
}
}
}
.chart-controls {
::v-deep .custom-select {
.el-input__wrapper {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
.el-input__inner {
color: #ffffff;
}
}
}
}
}
.chart {
width: 100%;
height: 3.5rem;
}
}
.compare-analysis {
background: rgba(255, 255, 255, 0.03);
border-radius: 0.08rem;
padding: 0.2rem;
margin-bottom: 0.16rem;
.analysis-header {
margin-bottom: 0.2rem;
.analysis-title {
font-size: 0.15rem;
color: #ffffff;
font-weight: bold;
padding-left: 0.12rem;
border-left: 0.04rem solid #15e1fd;
}
}
.analysis-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(2rem, 1fr));
gap: 0.15rem;
.analysis-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.15rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 0.06rem;
.analysis-label {
font-size: 0.13rem;
color: #ffffff;
opacity: 0.7;
margin-bottom: 0.08rem;
}
.analysis-value {
font-size: 0.18rem;
font-weight: bold;
margin-bottom: 0.05rem;
&.up {
color: #91CC75;
}
&.down {
color: #EE6666;
}
}
.analysis-percentage {
font-size: 0.12rem;
&.up {
color: #91CC75;
}
&.down {
color: #EE6666;
}
}
}
}
.analysis-hint {
display: flex;
align-items: center;
justify-content: center;
padding: 0.3rem;
color: #ffffff;
opacity: 0.6;
.hint-icon {
margin-right: 0.1rem;
font-size: 0.18rem;
width: 0.18rem;
height: 0.18rem;
fill: currentColor;
}
}
}
.warning-energy-analysis {
background: rgba(255, 255, 255, 0.03);
border-radius: 0.08rem;
padding: 0.2rem;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.2rem;
.section-title {
font-size: 0.15rem;
color: #ffffff;
font-weight: bold;
padding-left: 0.12rem;
border-left: 0.04rem solid #15e1fd;
}
.section-actions {
::v-deep .custom-select {
.el-input__wrapper {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
.el-input__inner {
color: #ffffff;
}
}
}
}
}
.warning-timeline-chart {
.timeline-header {
display: flex;
gap: 0.3rem;
padding: 0.15rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 0.06rem;
margin-bottom: 0.2rem;
.header-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
.label {
font-size: 0.12rem;
color: #ffffff;
opacity: 0.7;
margin-bottom: 0.05rem;
}
.value {
font-size: 0.18rem;
font-weight: bold;
color: #15e1fd;
&.warning-impact {
color: #EE6666;
}
}
}
}
.timeline-chart {
height: 3.5rem;
}
}
.warning-impact-table {
margin-top: 0.2rem;
.table-header {
margin-bottom: 0.15rem;
.table-title {
font-size: 0.14rem;
color: #ffffff;
font-weight: bold;
}
}
.table-container {
overflow-x: auto;
border-radius: 0.04rem;
background: rgba(255, 255, 255, 0.02);
.impact-table {
width: 100%;
border-collapse: collapse;
min-width: 14rem;
thead {
position: sticky;
top: 0;
z-index: 10;
tr {
background: linear-gradient(135deg, rgba(21, 225, 253, 0.1) 0%, rgba(145, 204, 117, 0.1) 100%);
th {
padding: 0.12rem 0.1rem;
text-align: left;
font-size: 0.13rem;
color: #15e1fd;
font-weight: 600;
border-bottom: 2px solid rgba(21, 225, 253, 0.3);
white-space: nowrap;
&:first-child {
padding-left: 0.15rem;
border-top-left-radius: 0.04rem;
}
&:last-child {
padding-right: 0.15rem;
border-top-right-radius: 0.04rem;
}
}
}
}
tbody {
tr {
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.02);
&:nth-child(even) {
background: rgba(255, 255, 255, 0.04);
}
&:hover {
background: rgba(21, 225, 253, 0.1);
transform: translateX(0.02rem);
}
td {
padding: 0.12rem 0.1rem;
font-size: 0.12rem;
color: #ffffff;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
vertical-align: middle;
&:first-child {
padding-left: 0.15rem;
}
&:last-child {
padding-right: 0.15rem;
}
&.energy-loss {
color: #EE6666;
}
&.energy-save {
color: #91CC75;
}
&.water-up {
color: #4facfe;
}
&.water-down {
color: #EE6666;
}
&.saving-drop {
color: #EE6666;
}
&.saving-rise {
color: #91CC75;
}
.title-cell {
max-width: 2rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
&:hover {
color: #15e1fd;
}
}
.level-badge {
display: inline-block;
padding: 0.03rem 0.1rem;
border-radius: 0.03rem;
font-size: 0.11rem;
font-weight: 500;
&.critical {
background: rgba(238, 102, 102, 0.2);
color: #EE6666;
border: 1px solid rgba(238, 102, 102, 0.4);
box-shadow: 0 0.04rem 0.08rem rgba(238, 102, 102, 0.2);
}
&.major {
background: rgba(250, 200, 88, 0.2);
color: #FAC858;
border: 1px solid rgba(250, 200, 88, 0.4);
box-shadow: 0 0.04rem 0.08rem rgba(250, 200, 88, 0.2);
}
&.minor {
background: rgba(145, 204, 117, 0.2);
color: #91CC75;
border: 1px solid rgba(145, 204, 117, 0.4);
box-shadow: 0 0.04rem 0.08rem rgba(145, 204, 117, 0.2);
}
}
.status-badge {
display: inline-block;
padding: 0.03rem 0.1rem;
border-radius: 0.03rem;
font-size: 0.11rem;
font-weight: 500;
&.pending {
background: rgba(238, 102, 102, 0.2);
color: #EE6666;
border: 1px solid rgba(238, 102, 102, 0.4);
}
&.processing {
background: rgba(250, 200, 88, 0.2);
color: #FAC858;
border: 1px solid rgba(250, 200, 88, 0.4);
}
&.resolved {
background: rgba(145, 204, 117, 0.2);
color: #91CC75;
border: 1px solid rgba(145, 204, 117, 0.4);
}
}
.action-buttons {
display: flex;
gap: 0.06rem;
.action-btn {
font-size: 0.11rem;
padding: 0.04rem 0.1rem;
}
.action-dropdown {
::v-deep .el-dropdown-menu.custom-dropdown-menu {
background: rgba(30, 30, 50, 0.95);
border: 1px solid rgba(21, 225, 253, 0.3);
.el-dropdown-menu__item {
color: #ffffff;
&:hover {
background: rgba(21, 225, 253, 0.1);
}
}
}
}
}
}
}
}
}
}
}
}
::v-deep .custom-dialog {
.el-dialog {
background: rgba(30, 30, 50, 0.95);
border: 1px solid rgba(21, 225, 253, 0.3);
}
.el-dialog__header {
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.el-dialog__title {
color: #ffffff;
}
.el-dialog__body {
color: #ffffff;
}
.custom-btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
color: #ffffff;
}
}
.warning-detail-content {
.detail-section {
margin-bottom: 0.3rem;
.section-title {
font-size: 0.14rem;
color: #ffffff;
font-weight: bold;
padding-left: 0.1rem;
border-left: 0.03rem solid #15e1fd;
margin-bottom: 0.15rem;
}
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.15rem;
.info-item {
display: flex;
align-items: center;
padding: 0.1rem;
background: rgba(255, 255, 255, 0.03);
border-radius: 0.04rem;
&.full-width {
grid-column: span 2;
}
.item-label {
font-size: 0.12rem;
color: #ffffff;
opacity: 0.7;
margin-right: 0.1rem;
min-width: 0.8rem;
}
.item-value {
font-size: 0.13rem;
color: #ffffff;
flex: 1;
&.level-badge {
display: inline-block;
padding: 0.03rem 0.1rem;
border-radius: 0.03rem;
font-size: 0.11rem;
font-weight: 500;
&.critical {
background: rgba(238, 102, 102, 0.2);
color: #EE6666;
}
&.major {
background: rgba(250, 200, 88, 0.2);
color: #FAC858;
}
&.minor {
background: rgba(145, 204, 117, 0.2);
color: #91CC75;
}
}
}
}
}
.impact-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 0.15rem;
.impact-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 0.2rem;
background: rgba(255, 255, 255, 0.03);
border-radius: 0.06rem;
.card-label {
font-size: 0.12rem;
color: #ffffff;
opacity: 0.7;
margin-bottom: 0.1rem;
}
.card-value {
font-size: 0.2rem;
font-weight: bold;
margin-bottom: 0.05rem;
&.energy-impact {
color: #EE6666;
}
&.water-impact {
color: #4facfe;
}
&.saving-impact {
color: #EE6666;
}
&.cost-impact {
color: #FAC858;
}
}
.card-desc {
font-size: 0.11rem;
color: #ffffff;
opacity: 0.6;
}
}
}
}
.energy-comparison-chart {
height: 3rem;
}
}
@media (max-width: 1485px) {
.indicator-cards {
grid-template-columns: repeat(auto-fit, minmax(2rem, 1fr));
}
.analysis-content {
grid-template-columns: repeat(2, 1fr);
}
.impact-cards {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.indicator-cards {
grid-template-columns: 1fr;
}
.analysis-content {
grid-template-columns: 1fr;
}
.impact-cards {
grid-template-columns: 1fr;
}
.info-grid {
grid-template-columns: 1fr;
}
}
</style>