From 3d17f7788b56ff5e601b069c6841ab723c20367d Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 11 九月 2025 14:17:31 +0800
Subject: [PATCH] 碳排放热力图
---
src/components/Echarts/echarts.vue | 7
src/views/energyManagement/carbonManagement/index.vue | 1553 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 1,559 insertions(+), 1 deletions(-)
diff --git a/src/components/Echarts/echarts.vue b/src/components/Echarts/echarts.vue
index 29abba8..a386bb7 100644
--- a/src/components/Echarts/echarts.vue
+++ b/src/components/Echarts/echarts.vue
@@ -76,6 +76,10 @@
type: Array,
default: () => []
},
+ visualMap: {
+ type: Object,
+ default: () => ({})
+ },
option: {
type: Object,
default: () => ({})
@@ -121,6 +125,7 @@
grid: props.grid,
legend: props.legend,
tooltip: props.tooltip,
+ visualMap: Object.keys(props.visualMap).length ? props.visualMap : undefined,
}
chartInstance.clear()
@@ -149,7 +154,7 @@
// Watch all reactive props that affect the chart
watch(
- () => [props.xAxis, props.series, props.legend, props.tooltip],
+ () => [props.xAxis, props.yAxis, props.series, props.legend, props.tooltip, props.visualMap],
() => {
if (chartInstance) {
renderChart()
diff --git a/src/views/energyManagement/carbonManagement/index.vue b/src/views/energyManagement/carbonManagement/index.vue
new file mode 100644
index 0000000..5a4be25
--- /dev/null
+++ b/src/views/energyManagement/carbonManagement/index.vue
@@ -0,0 +1,1553 @@
+<template>
+ <div class="carbon-management">
+ <!-- 椤甸潰澶撮儴 -->
+ <div class="page-header">
+ <div class="header-content">
+ <h1 class="page-title">纰虫帓鏀剧鐞嗙郴缁�</h1>
+ <p class="page-subtitle">鍩轰簬ISO 14064鏍囧噯 路 GHG Protocol鏍哥畻鏍囧噯</p>
+ </div>
+ <div class="header-stats">
+ <div class="stat-item">
+ <span class="stat-label">鎬荤⒊鎺掓斁閲�</span>
+ <span class="stat-value">{{totalEmissions}} tCO鈧俥</span>
+ </div>
+ <div class="stat-item">
+ <span class="stat-label">鏈湀鍑忔帓</span>
+ <span class="stat-value reduction">-{{monthlyReduction}}%</span>
+ </div>
+ <div class="stat-item">
+ <span class="stat-label">纰充腑鍜岃繘搴�</span>
+ <span class="stat-value">{{neutralProgress}}%</span>
+ </div>
+ </div>
+ </div>
+
+ <!-- 涓昏鍐呭鍖哄煙 -->
+ <div class="dashboard-content">
+ <!-- 椤堕儴鏁版嵁闈㈡澘 -->
+ <div class="top-panels">
+ <div class="data-panel top-left">
+ <div class="panel-title">褰撳墠纰虫帓鏀�</div>
+ <div class="panel-value">{{carbonData.scope1}} <span class="unit">tCO鈧俥</span></div>
+ <div class="panel-subtitle">鑼冨洿1鐩存帴鎺掓斁</div>
+ </div>
+ <div class="data-panel top-center">
+ <div class="panel-title">鑳借�楃洃娴�</div>
+ <div class="panel-value">{{carbonData.scope2}} <span class="unit">tCO鈧俥</span></div>
+ <div class="panel-subtitle">鑼冨洿2闂存帴鎺掓斁</div>
+ </div>
+ <div class="data-panel top-right">
+ <div class="panel-title">渚涘簲閾炬帓鏀�</div>
+ <div class="panel-value">{{carbonData.scope3}} <span class="unit">tCO鈧俥</span></div>
+ <div class="panel-subtitle">鑼冨洿3渚涘簲閾炬帓鏀�</div>
+ </div>
+ <div class="data-panel top-far-right">
+ <div class="panel-title">鍑忔帓杩涘害</div>
+ <div class="panel-value">{{neutralProgress}} <span class="unit">%</span></div>
+ <div class="panel-subtitle">纰充腑鍜岀洰鏍�</div>
+ </div>
+ </div>
+
+ <!-- 涓績涓昏鍥惧尯鍩� -->
+ <div class="center-main-view">
+ <!-- 宸︿晶鎺у埗闈㈡澘 -->
+ <div class="left-control-panel">
+ <div class="control-section">
+ <div class="section-title">纰虫帓鏀捐寖鍥�</div>
+ <el-radio-group v-model="selectedScope" @change="updateScopeData" class="vertical-radio">
+ <el-radio-button :value="'all'">鍏ㄩ儴鑼冨洿</el-radio-button>
+ <el-radio-button :value="'scope1'">鑼冨洿1</el-radio-button>
+ <el-radio-button :value="'scope2'">鑼冨洿2</el-radio-button>
+ <el-radio-button :value="'scope3'">鑼冨洿3</el-radio-button>
+ </el-radio-group>
+ </div>
+ <div class="control-section">
+ <div class="section-title">鐩戞祴灞傜骇</div>
+ <el-radio-group v-model="heatmapLevel" @change="updateHeatmapLevel" class="vertical-radio">
+ <el-radio-button :value="'device'">璁惧绾�</el-radio-button>
+ <el-radio-button :value="'line'">浜х嚎绾�</el-radio-button>
+ <el-radio-button :value="'enterprise'">浼佷笟绾�</el-radio-button>
+ </el-radio-group>
+ </div>
+ </div>
+
+ <!-- 涓績鐑姏鍥� -->
+ <div class="main-heatmap">
+ <div class="heatmap-header">
+ <h2 class="main-title">纰宠冻杩圭儹鍔涘浘鍒嗘瀽</h2>
+ <div class="date-selector">
+ <el-date-picker
+ v-model="selectedDate"
+ type="date"
+ placeholder="閫夋嫨鏃ユ湡"
+ size="small"
+ @change="updateHeatmapData"
+ />
+ </div>
+ </div>
+ <div class="heatmap-view">
+ <Echarts ref="heatmapChart"
+ :series="heatmapSeries"
+ :xAxis="heatmapXAxis"
+ :yAxis="heatmapYAxis"
+ :tooltip="heatmapTooltip"
+ :visualMap="heatmapVisualMap"
+ :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
+ style="height: 450px"></Echarts>
+ </div>
+ </div>
+
+ <!-- 鍙充晶鏁版嵁闈㈡澘 -->
+ <div class="right-data-panel">
+ <div class="data-section">
+ <div class="section-title">瀹炴椂鐩戞帶</div>
+ <div class="mini-chart">
+ <Echarts ref="realtimeChart"
+ :series="realtimeSeries"
+ :xAxis="realtimeXAxis"
+ :chartStyle="chartStyle"
+ :yAxis="realtimeYAxis"
+ :tooltip="realtimeTooltip"
+ :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
+ style="height: 300px"></Echarts>
+ </div>
+ </div>
+ <div class="data-section">
+ <div class="section-title">瓒嬪娍鍒嗘瀽</div>
+ <div class="trend-controls">
+ <el-radio-group v-model="trendPeriod" size="small" @change="updateTrendData">
+ <el-radio-button :value="'week'">鍛�</el-radio-button>
+ <el-radio-button :value="'month'">鏈�</el-radio-button>
+ <el-radio-button :value="'year'">骞�</el-radio-button>
+ </el-radio-group>
+ </div>
+ <div class="mini-chart">
+ <Echarts ref="trendChart"
+ :series="trendSeries"
+ :xAxis="trendXAxis"
+ :yAxis="trendYAxis"
+ :tooltip="trendTooltip"
+ :chartStyle="chartStyle"
+ :legend="trendLegend"
+ :options="{backgroundColor: 'transparent', textStyle: {color: '#B8C8E0'}}"
+ style="height: 200px"></Echarts>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <!-- 搴曢儴杩涘害闈㈡澘 -->
+ <div class="bottom-progress-panel">
+ <div class="progress-section">
+ <div class="progress-title">2024骞村噺鎺掔洰鏍�</div>
+ <div class="progress-data">
+ <span class="current">{{reductionTarget.current}}</span>
+ <span class="separator">/</span>
+ <span class="target">{{reductionTarget.target}} tCO鈧俥</span>
+ </div>
+ <el-progress :percentage="reductionTarget.percentage" :stroke-width="6" color="#00E676"/>
+ </div>
+ <div class="progress-section">
+ <div class="progress-title">纰充腑鍜岃繘搴�</div>
+ <div class="progress-data">
+ <span class="current">{{neutralTarget.current}}</span>
+ <span class="separator">/</span>
+ <span class="target">{{neutralTarget.target}} tCO鈧俥</span>
+ </div>
+ <el-progress :percentage="neutralTarget.percentage" :stroke-width="6" color="#00D4FF"/>
+ </div>
+ </div>
+
+ <!-- 搴曢儴鏁版嵁琛ㄦ牸 -->
+ <div class="bottom-data-table">
+ <div class="table-panel">
+ <div class="table-header">
+ <h3 class="table-title">纰虫帓鏀捐缁嗘暟鎹�</h3>
+ <div class="table-controls">
+ <el-input
+ v-model="searchKeyword"
+ placeholder="鎼滅储璁惧鎴栦骇绾�"
+ size="small"
+ style="width: 200px; margin-right: 10px;"
+ />
+ <el-button type="primary" size="small" @click="exportData">瀵煎嚭鏁版嵁</el-button>
+ </div>
+ </div>
+ <el-table :data="filteredTableData" style="width: 100%" height="180">
+ <el-table-column prop="name" label="璁惧/浜х嚎" width="150"/>
+ <el-table-column prop="type" label="绫诲瀷" width="100"/>
+ <el-table-column prop="scope1" label="鑼冨洿1鎺掓斁" width="120"/>
+ <el-table-column prop="scope2" label="鑼冨洿2鎺掓斁" width="120"/>
+ <el-table-column prop="scope3" label="鑼冨洿3鎺掓斁" width="120"/>
+ <el-table-column prop="total" label="鎬绘帓鏀鹃噺" width="120"/>
+ <el-table-column prop="efficiency" label="纰虫晥鐜�" width="100"/>
+ <el-table-column prop="status" label="鐘舵��" width="100">
+ <template #default="scope">
+ <el-tag :type="getStatusType(scope.row.status)">{{scope.row.status}}</el-tag>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script setup>
+import { ref, reactive, onMounted, onBeforeUnmount, computed } from 'vue'
+import * as echarts from 'echarts'
+import Echarts from '@/components/Echarts/echarts.vue'
+
+// 鍝嶅簲寮忔暟鎹�
+const selectedScope = ref('all')
+const heatmapLevel = ref('device')
+const selectedDate = ref(new Date())
+const trendPeriod = ref('week')
+const searchKeyword = ref('')
+
+// 纰虫帓鏀炬暟鎹�
+const carbonData = ref({
+ scope1: 125.6,
+ scope2: 89.3,
+ scope3: 234.7
+})
+const chartStyle = {
+ width: '96%',
+ height: '110%' // 璁剧疆鍥捐〃瀹瑰櫒鐨勯珮搴�
+}
+// 璁$畻灞炴��
+const totalEmissions = computed(() => {
+ return (carbonData.value.scope1 + carbonData.value.scope2 + carbonData.value.scope3).toFixed(1)
+})
+
+const monthlyReduction = ref(8.5)
+
+// 璁$畻纰充腑鍜岃繘搴︾櫨鍒嗘瘮
+const neutralProgress = computed(() => {
+ return Math.round(neutralTarget.value.percentage)
+})
+
+// 鍑忔帓鐩爣鏁版嵁
+const reductionTarget = ref({
+ current: 320.5,
+ target: 500,
+ percentage: 64.1
+})
+
+const neutralTarget = ref({
+ current: 1250,
+ target: 3800,
+ percentage: 32.9
+})
+
+// 瀹炴椂鐩戞帶鍥捐〃閰嶇疆
+const realtimeSeries = ref([
+ {
+ name: '瀹炴椂纰虫帓鏀�',
+ type: 'line',
+ smooth: true,
+ data: generateRealtimeData(),
+ itemStyle: {
+ color: '#FF6B6B'
+ },
+ areaStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: 'rgba(255, 107, 107, 0.3)' },
+ { offset: 1, color: 'rgba(255, 107, 107, 0.1)' }
+ ])
+ }
+ }
+])
+
+const realtimeXAxis = [{
+ type: 'category',
+ data: Array.from({length: 24}, (_, i) => `${i.toString().padStart(2, '0')}:00`),
+ axisLabel: { color: '#B8C8E0' }
+}]
+
+const realtimeYAxis = [{
+ type: 'value',
+ name: 'tCO鈧俥/h',
+ axisLabel: { color: '#B8C8E0' },
+ nameTextStyle: { color: '#B8C8E0' }
+}]
+
+const realtimeTooltip = {
+ trigger: 'axis',
+ formatter: '{b}: {c} tCO鈧俥/h'
+}
+
+// 鐑姏鍥鹃厤缃�
+const heatmapSeries = ref([
+ {
+ name: '纰虫帓鏀鹃噺',
+ type: 'heatmap',
+ data: generateHeatmapData(),
+ label: {
+ show: false
+ },
+ emphasis: {
+ itemStyle: {
+ shadowBlur: 10,
+ shadowColor: 'rgba(0, 0, 0, 0.5)'
+ }
+ }
+ }
+])
+
+const heatmapXAxis = [{
+ type: 'category',
+ data: Array.from({length: 24}, (_, i) => `${i}:00`),
+ splitArea: { show: true },
+ axisLabel: { color: '#B8C8E0' }
+}]
+
+const heatmapYAxis = [{
+ type: 'category',
+ data: ['璁惧A', '璁惧B', '璁惧C', '璁惧D', '璁惧E', '璁惧F', '璁惧G'],
+ splitArea: { show: true },
+ axisLabel: { color: '#B8C8E0' }
+}]
+
+const heatmapTooltip = {
+ trigger: 'item',
+ formatter: function (params) {
+ const [hour, device] = params.data
+ const value = params.value[2]
+ return `璁惧: ${heatmapYAxis[0].data[device]}<br/>鏃堕棿: ${hour}:00<br/>纰虫帓鏀鹃噺: ${value} tCO鈧俥`
+ }
+}
+
+const heatmapVisualMap = ref({
+ min: 0,
+ max: 50,
+ calculable: true,
+ orient: 'horizontal',
+ left: 'center',
+ bottom: '5%',
+ inRange: {
+ color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
+ },
+ textStyle: { color: '#B8C8E0' }
+})
+
+// 瓒嬪娍鍒嗘瀽鍥捐〃閰嶇疆
+const trendSeries = ref([
+ {
+ name: '鑼冨洿1',
+ type: 'line',
+ data: [120, 132, 101, 134, 90, 230, 210],
+ itemStyle: { color: '#FF6B6B' }
+ },
+ {
+ name: '鑼冨洿2',
+ type: 'line',
+ data: [220, 182, 191, 234, 290, 330, 310],
+ itemStyle: { color: '#4ECDC4' }
+ },
+ {
+ name: '鑼冨洿3',
+ type: 'line',
+ data: [150, 232, 201, 154, 190, 330, 410],
+ itemStyle: { color: '#45B7D1' }
+ }
+])
+
+const trendXAxis = [{
+ type: 'category',
+ data: ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩'],
+ axisLabel: { color: '#B8C8E0' }
+}]
+
+const trendYAxis = [{
+ type: 'value',
+ name: 'tCO鈧俥',
+ axisLabel: { color: '#B8C8E0' },
+ nameTextStyle: { color: '#B8C8E0' }
+}]
+
+const trendTooltip = {
+ trigger: 'axis'
+}
+
+const trendLegend = {
+ data: ['鑼冨洿1', '鑼冨洿2', '鑼冨洿3'],
+ textStyle: { color: '#B8C8E0' }
+}
+
+// 琛ㄦ牸鏁版嵁
+const carbonTableData = ref([
+ { name: '鐢熶骇绾緼', type: '浜х嚎', scope1: 45.2, scope2: 32.1, scope3: 18.7, total: 96.0, efficiency: '鑹ソ', status: '姝e父' },
+ { name: '璁惧B-01', type: '璁惧', scope1: 12.5, scope2: 8.3, scope3: 5.2, total: 26.0, efficiency: '浼樼', status: '姝e父' },
+ { name: '鐢熶骇绾緾', type: '浜х嚎', scope1: 38.7, scope2: 28.9, scope3: 15.4, total: 83.0, efficiency: '鑹ソ', status: '鍛婅' },
+ { name: '璁惧D-02', type: '璁惧', scope1: 15.8, scope2: 11.2, scope3: 7.1, total: 34.1, efficiency: '涓�鑸�', status: '姝e父' },
+ { name: '鐢熶骇绾縀', type: '浜х嚎', scope1: 52.3, scope2: 39.6, scope3: 22.8, total: 114.7, efficiency: '寰呬紭鍖�', status: '鍛婅' }
+])
+
+// 鐢熸垚瀹炴椂鏁版嵁
+function generateRealtimeData() {
+ return Array.from({length: 24}, () => (Math.random() * 20 + 10).toFixed(1))
+}
+
+// 鐢熸垚鐑姏鍥炬暟鎹�
+function generateHeatmapData() {
+ const data = []
+ let yAxisLength = 7 // 榛樿璁惧绾�
+ let baseMultiplier = 1 // 鍩虹鍊嶆暟
+
+ // 鏍规嵁灞傜骇纭畾Y杞撮暱搴﹀拰鏁版嵁鑼冨洿
+ if (heatmapLevel.value === 'line') {
+ yAxisLength = 5
+ baseMultiplier = 2 // 浜х嚎绾ф暟鎹洿澶�
+ } else if (heatmapLevel.value === 'enterprise') {
+ yAxisLength = 3
+ baseMultiplier = 4 // 浼佷笟绾ф暟鎹渶澶�
+ }
+
+ for (let i = 0; i < yAxisLength; i++) {
+ for (let j = 0; j < 24; j++) {
+ let value
+ // 绠�鍖栫殑鏃堕棿娈甸�昏緫
+ if (j >= 8 && j <= 18) {
+ // 宸ヤ綔鏃堕棿鎺掓斁閲忚緝楂�
+ value = Math.random() * 30 + 20
+ } else if (j >= 19 && j <= 22) {
+ // 鏅氶棿鎺掓斁閲忎腑绛�
+ value = Math.random() * 20 + 10
+ } else {
+ // 娣卞鍜屽噷鏅ㄦ帓鏀鹃噺杈冧綆
+ value = Math.random() * 10 + 2
+ }
+
+ // 娣诲姞璁惧宸紓鍜屽眰绾у�嶆暟
+ value *= (0.8 + i * 0.1) * baseMultiplier
+
+ data.push([j, i, Math.round(value * 10) / 10])
+ }
+ }
+ return data
+}
+
+// 鏇存柊鑼冨洿鏁版嵁
+function updateScopeData() {
+ // 鏍规嵁閫夋嫨鐨勮寖鍥存洿鏂版墍鏈夌浉鍏冲浘琛ㄦ暟鎹�
+ const scopeMultiplier = {
+ 'all': 1,
+ 'scope1': 0.3,
+ 'scope2': 0.4,
+ 'scope3': 0.3
+ }
+
+ const multiplier = scopeMultiplier[selectedScope.value] || 1
+
+ // 鏇存柊纰虫帓鏀炬暟鎹樉绀�
+ if (selectedScope.value === 'all') {
+ carbonData.value = {
+ scope1: 125.6,
+ scope2: 89.3,
+ scope3: 234.7
+ }
+ } else {
+ const baseTotal = 125.6 + 89.3 + 234.7
+ carbonData.value = {
+ scope1: selectedScope.value === 'scope1' ? 125.6 : 0,
+ scope2: selectedScope.value === 'scope2' ? 89.3 : 0,
+ scope3: selectedScope.value === 'scope3' ? 234.7 : 0
+ }
+ }
+
+ // 鏇存柊鐑姏鍥炬暟鎹�
+ heatmapSeries.value[0].data = generateHeatmapData().map(item => [
+ item[0], item[1], Math.round(item[2] * multiplier * 10) / 10
+ ])
+
+ // 鏇存柊瀹炴椂鐩戞帶鏁版嵁
+ realtimeSeries.value[0].data = generateRealtimeData().map(val =>
+ Math.round(parseFloat(val) * multiplier * 10) / 10
+ )
+}
+
+// 鏇存柊鐑姏鍥惧眰绾�
+function updateHeatmapLevel() {
+ // 鏍规嵁灞傜骇鏇存柊Y杞存暟鎹拰visualMap鑼冨洿
+ if (heatmapLevel.value === 'device') {
+ heatmapYAxis[0].data = ['閿呯倝A', '鍘嬬缉鏈築', '鍐峰嵈濉擟', '椋庢満D', '娉礒', '鍙樺帇鍣‵', '鐢垫満G']
+ heatmapVisualMap.value.max = 50
+ } else if (heatmapLevel.value === 'line') {
+ heatmapYAxis[0].data = ['鐢熶骇绾�1', '鐢熶骇绾�2', '鐢熶骇绾�3', '鐢熶骇绾�4', '鐢熶骇绾�5']
+ heatmapVisualMap.value.max = 100
+ } else {
+ heatmapYAxis[0].data = ['鍘傚尯A', '鍘傚尯B', '鍘傚尯C']
+ heatmapVisualMap.value.max = 200
+ }
+
+ // 鏇存柊鐑姏鍥炬暟鎹�
+ heatmapSeries.value[0].data = generateHeatmapData()
+
+ // 鏇存柊琛ㄦ牸鏁版嵁浠ュ尮閰嶅綋鍓嶅眰绾�
+ updateTableDataForLevel()
+}
+
+// 鏍规嵁灞傜骇鏇存柊琛ㄦ牸鏁版嵁
+function updateTableDataForLevel() {
+ const levelConfigs = {
+ device: [
+ { name: '閿呯倝A', type: '璁惧', scope1: 45.2, scope2: 32.1, scope3: 18.7, total: 96.0, efficiency: '鑹ソ', status: '姝e父' },
+ { name: '鍘嬬缉鏈築', type: '璁惧', scope1: 38.5, scope2: 28.3, scope3: 15.2, total: 82.0, efficiency: '浼樼', status: '姝e父' },
+ { name: '鍐峰嵈濉擟', type: '璁惧', scope1: 22.8, scope2: 18.9, scope3: 12.3, total: 54.0, efficiency: '鑹ソ', status: '鍛婅' },
+ { name: '椋庢満D', type: '璁惧', scope1: 15.6, scope2: 12.4, scope3: 8.1, total: 36.1, efficiency: '涓�鑸�', status: '姝e父' },
+ { name: '娉礒', type: '璁惧', scope1: 12.3, scope2: 9.8, scope3: 6.4, total: 28.5, efficiency: '浼樼', status: '姝e父' }
+ ],
+ line: [
+ { name: '鐢熶骇绾�1', type: '浜х嚎', scope1: 125.6, scope2: 89.3, scope3: 56.8, total: 271.7, efficiency: '鑹ソ', status: '姝e父' },
+ { name: '鐢熶骇绾�2', type: '浜х嚎', scope1: 98.4, scope2: 72.1, scope3: 45.2, total: 215.7, efficiency: '浼樼', status: '姝e父' },
+ { name: '鐢熶骇绾�3', type: '浜х嚎', scope1: 87.2, scope2: 65.8, scope3: 41.6, total: 194.6, efficiency: '鑹ソ', status: '鍛婅' },
+ { name: '鐢熶骇绾�4', type: '浜х嚎', scope1: 76.9, scope2: 58.3, scope3: 37.1, total: 172.3, efficiency: '涓�鑸�', status: '姝e父' },
+ { name: '鐢熶骇绾�5', type: '浜х嚎', scope1: 65.7, scope2: 49.2, scope3: 31.8, total: 146.7, efficiency: '寰呬紭鍖�', status: '鍛婅' }
+ ],
+ enterprise: [
+ { name: '鍘傚尯A', type: '鍘傚尯', scope1: 456.8, scope2: 334.7, scope3: 212.5, total: 1004.0, efficiency: '鑹ソ', status: '姝e父' },
+ { name: '鍘傚尯B', type: '鍘傚尯', scope1: 387.2, scope2: 289.6, scope3: 184.3, total: 861.1, efficiency: '浼樼', status: '姝e父' },
+ { name: '鍘傚尯C', type: '鍘傚尯', scope1: 298.5, scope2: 223.8, scope3: 142.7, total: 665.0, efficiency: '鑹ソ', status: '鍛婅' }
+ ]
+ }
+
+ carbonTableData.value = levelConfigs[heatmapLevel.value] || levelConfigs.device
+}
+
+// 鏇存柊鐑姏鍥炬暟鎹紙鏃ユ湡鍙樺寲鏃讹級
+function updateHeatmapData() {
+ heatmapSeries.value[0].data = generateHeatmapData()
+
+ // 鍚屾椂鏇存柊鍏朵粬鐩稿叧鏁版嵁
+ updateScopeData()
+}
+
+// 鏇存柊瓒嬪娍鏁版嵁
+function updateTrendData() {
+ const trendDataConfigs = {
+ week: {
+ xAxisData: ['鍛ㄤ竴', '鍛ㄤ簩', '鍛ㄤ笁', '鍛ㄥ洓', '鍛ㄤ簲', '鍛ㄥ叚', '鍛ㄦ棩'],
+ scope1Data: [120, 132, 101, 134, 90, 80, 75],
+ scope2Data: [220, 182, 191, 234, 190, 150, 140],
+ scope3Data: [150, 232, 201, 154, 190, 120, 110]
+ },
+ month: {
+ xAxisData: ['1鏈�', '2鏈�', '3鏈�', '4鏈�', '5鏈�', '6鏈�', '7鏈�', '8鏈�', '9鏈�', '10鏈�', '11鏈�', '12鏈�'],
+ scope1Data: [1200, 1150, 1300, 1250, 1180, 1320, 1280, 1350, 1220, 1290, 1160, 1100],
+ scope2Data: [2200, 2100, 2350, 2280, 2150, 2400, 2320, 2450, 2180, 2380, 2120, 2050],
+ scope3Data: [1800, 1750, 1950, 1880, 1820, 2000, 1920, 2100, 1850, 1980, 1780, 1720]
+ },
+ year: {
+ xAxisData: ['2019', '2020', '2021', '2022', '2023', '2024'],
+ scope1Data: [14500, 14200, 13800, 13500, 13100, 12800],
+ scope2Data: [26800, 26200, 25600, 25000, 24400, 23800],
+ scope3Data: [22400, 21800, 21200, 20600, 20000, 19400]
+ }
+ }
+
+ const config = trendDataConfigs[trendPeriod.value] || trendDataConfigs.week
+
+ // 鏇存柊X杞存暟鎹�
+ trendXAxis[0].data = config.xAxisData
+
+ // 鏇存柊绯诲垪鏁版嵁
+ trendSeries.value = [
+ {
+ name: '鑼冨洿1',
+ type: 'line',
+ data: config.scope1Data,
+ itemStyle: { color: '#FF6B6B' },
+ smooth: true
+ },
+ {
+ name: '鑼冨洿2',
+ type: 'line',
+ data: config.scope2Data,
+ itemStyle: { color: '#4ECDC4' },
+ smooth: true
+ },
+ {
+ name: '鑼冨洿3',
+ type: 'line',
+ data: config.scope3Data,
+ itemStyle: { color: '#45B7D1' },
+ smooth: true
+ }
+ ]
+}
+
+// 鑾峰彇鐘舵�佺被鍨�
+function getStatusType(status) {
+ switch (status) {
+ case '姝e父': return 'success'
+ case '鍛婅': return 'warning'
+ case '寮傚父': return 'danger'
+ default: return 'info'
+ }
+}
+
+// 瀵煎嚭鏁版嵁
+function exportData() {
+ // 鍑嗗瀵煎嚭鏁版嵁
+ const exportDataSet = {
+ 鍩烘湰淇℃伅: {
+ 瀵煎嚭鏃堕棿: new Date().toLocaleString('zh-CN'),
+ 鏁版嵁灞傜骇: heatmapLevel.value === 'device' ? '璁惧绾�' : heatmapLevel.value === 'line' ? '浜х嚎绾�' : '浼佷笟绾�',
+ 閫夋嫨鑼冨洿: selectedScope.value === 'all' ? '鍏ㄩ儴鑼冨洿' : `鑼冨洿${selectedScope.value.slice(-1)}`,
+ 閫夋嫨鏃ユ湡: selectedDate.value ? selectedDate.value.toLocaleDateString('zh-CN') : '浠婃棩'
+ },
+ 纰虫帓鏀剧粺璁�: {
+ 鑼冨洿1鐩存帴鎺掓斁: carbonData.value.scope1 + ' tCO鈧俥',
+ 鑼冨洿2闂存帴鎺掓斁: carbonData.value.scope2 + ' tCO鈧俥',
+ 鑼冨洿3渚涘簲閾炬帓鏀�: carbonData.value.scope3 + ' tCO鈧俥',
+ 鎬绘帓鏀鹃噺: totalEmissions.value + ' tCO鈧俥'
+ },
+ 璇︾粏鏁版嵁: carbonTableData.value,
+ 鐑姏鍥炬暟鎹�: heatmapSeries.value[0].data.map(item => ({
+ 鏃堕棿: `${item[0]}:00`,
+ 璁惧搴忓彿: item[1],
+ 璁惧鍚嶇О: heatmapYAxis.data[item[1]],
+ 纰虫帓鏀鹃噺: item[2] + ' tCO鈧俥'
+ }))
+ }
+
+ // 鍒涘缓CSV鍐呭
+ let csvContent = '\uFEFF' // BOM for UTF-8
+
+ // 鍩烘湰淇℃伅
+ csvContent += '鍩烘湰淇℃伅\n'
+ Object.entries(exportDataSet.鍩烘湰淇℃伅).forEach(([key, value]) => {
+ csvContent += `${key},${value}\n`
+ })
+ csvContent += '\n'
+
+ // 纰虫帓鏀剧粺璁�
+ csvContent += '纰虫帓鏀剧粺璁n'
+ Object.entries(exportDataSet.纰虫帓鏀剧粺璁�).forEach(([key, value]) => {
+ csvContent += `${key},${value}\n`
+ })
+ csvContent += '\n'
+
+ // 璇︾粏鏁版嵁琛ㄦ牸
+ csvContent += '璇︾粏鏁版嵁\n'
+ csvContent += '鍚嶇О,绫诲瀷,鑼冨洿1鎺掓斁,鑼冨洿2鎺掓斁,鑼冨洿3鎺掓斁,鎬绘帓鏀鹃噺,纰虫晥鐜�,鐘舵�乗n'
+ exportDataSet.璇︾粏鏁版嵁.forEach(row => {
+ csvContent += `${row.name},${row.type},${row.scope1},${row.scope2},${row.scope3},${row.total},${row.efficiency},${row.status}\n`
+ })
+ csvContent += '\n'
+
+ // 鐑姏鍥炬暟鎹紙鍓�50鏉★級
+ csvContent += '鐑姏鍥炬暟鎹紙鍓�50鏉★級\n'
+ csvContent += '鏃堕棿,璁惧鍚嶇О,纰虫帓鏀鹃噺\n'
+ exportDataSet.鐑姏鍥炬暟鎹�.slice(0, 50).forEach(row => {
+ csvContent += `${row.鏃堕棿},${row.璁惧鍚嶇О},${row.纰虫帓鏀鹃噺}\n`
+ })
+
+ // 鍒涘缓涓嬭浇閾炬帴
+ const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })
+ const link = document.createElement('a')
+ const url = URL.createObjectURL(blob)
+ link.setAttribute('href', url)
+ link.setAttribute('download', `纰虫帓鏀炬暟鎹甠${new Date().toISOString().slice(0, 10)}.csv`)
+ link.style.visibility = 'hidden'
+ document.body.appendChild(link)
+ link.click()
+ document.body.removeChild(link)
+
+ // 鏄剧ず鎴愬姛娑堟伅
+ console.log('纰虫帓鏀炬暟鎹鍑烘垚鍔�')
+}
+
+// 鎼滅储杩囨护鍔熻兘
+const filteredTableData = computed(() => {
+ if (!searchKeyword.value) {
+ return carbonTableData.value
+ }
+ return carbonTableData.value.filter(item =>
+ item.name.toLowerCase().includes(searchKeyword.value.toLowerCase()) ||
+ item.type.toLowerCase().includes(searchKeyword.value.toLowerCase())
+ )
+})
+
+// 鐑姏鍥剧偣鍑讳簨浠跺鐞�
+function handleHeatmapClick(params) {
+ if (params.componentType === 'series') {
+ const [hour, deviceIndex, value] = params.data
+ const deviceName = heatmapYAxis.data[deviceIndex]
+ console.log(`鐐瑰嚮浜嗚澶�: ${deviceName}, 鏃堕棿: ${hour}:00, 鎺掓斁閲�: ${value} tCO鈧俥`)
+
+ // 鍙互鍦ㄨ繖閲屾坊鍔犺缁嗕俊鎭脊绐楁垨璺宠浆鍒拌缁嗛〉闈�
+ }
+}
+
+onMounted(() => {
+ // 椤甸潰鍔犺浇瀹屾垚鍚庣殑鍒濆鍖栨搷浣�
+ console.log('纰崇鐞嗛〉闈㈠凡鍔犺浇')
+
+ // 鍒濆鍖栫儹鍔涘浘鏁版嵁
+ updateHeatmapLevel()
+
+ // 鍒濆鍖栬秼鍔挎暟鎹�
+ updateTrendData()
+
+ // 鍒濆鍖栬寖鍥存暟鎹�
+ updateScopeData()
+
+ // 璁剧疆瀹氭椂鍣紝姣�30绉掓洿鏂颁竴娆″疄鏃舵暟鎹�
+ const timer = setInterval(() => {
+ realtimeSeries.value[0].data = generateRealtimeData()
+ }, 30000)
+
+ // 娓呯悊瀹氭椂鍣�
+ onBeforeUnmount(() => {
+ clearInterval(timer)
+ })
+})
+
+// 娣诲姞鐑姏鍥剧偣鍑讳簨浠剁粦瀹�
+function bindHeatmapEvents() {
+ // 杩欎釜鍑芥暟鍙互鐢ㄦ潵缁戝畾鐑姏鍥剧殑鐐瑰嚮浜嬩欢
+ // 鍦ㄥ疄闄呬娇鐢ㄤ腑锛屽彲浠ラ�氳繃ECharts鐨勪簨浠剁郴缁熸潵瀹炵幇
+}
+</script>
+
+<style scoped>
+.carbon-management {
+ min-height: 100vh;
+ background:
+ radial-gradient(ellipse at top, rgba(29, 78, 216, 0.15), transparent 50%),
+ radial-gradient(ellipse at bottom, rgba(139, 92, 246, 0.15), transparent 50%),
+ linear-gradient(135deg, #0a0f1c 0%, #1e293b 25%, #0f172a 50%, #1e293b 75%, #0a0f1c 100%);
+ padding: 20px;
+ font-family: 'Inter', 'Microsoft YaHei', sans-serif;
+ overflow: hidden;
+ position: relative;
+}
+
+.carbon-management::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background:
+ radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.1) 0%, transparent 50%),
+ radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.1) 0%, transparent 50%),
+ radial-gradient(circle at 40% 40%, rgba(120, 219, 255, 0.05) 0%, transparent 50%);
+ pointer-events: none;
+
+}
+
+
+
+.page-header {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.95) 0%, rgba(30, 41, 59, 0.9) 100%),
+ radial-gradient(circle at top right, rgba(59, 130, 246, 0.1), transparent 50%);
+ border: 1px solid rgba(148, 163, 184, 0.2);
+ border-radius: 20px;
+ padding: 40px;
+ margin-bottom: 30px;
+ box-shadow:
+ 0 25px 50px -12px rgba(0, 0, 0, 0.4),
+ 0 0 0 1px rgba(255, 255, 255, 0.05),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ position: relative;
+ overflow: hidden;
+ backdrop-filter: blur(20px);
+
+}
+
+.page-header:hover {
+ transform: translateY(-2px);
+ box-shadow:
+ 0 32px 64px -12px rgba(0, 0, 0, 0.5),
+ 0 0 0 1px rgba(255, 255, 255, 0.1),
+ inset 0 1px 0 rgba(255, 255, 255, 0.15);
+}
+
+.page-header::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background:
+ linear-gradient(45deg, rgba(59, 130, 246, 0.08) 0%, rgba(147, 51, 234, 0.08) 50%, rgba(236, 72, 153, 0.08) 100%);
+ pointer-events: none;
+
+}
+
+
+
+.header-content {
+ flex: 1;
+ position: relative;
+ z-index: 1;
+}
+
+.page-title {
+ font-size: 28px;
+ font-weight: bold;
+ color: #ffffff;
+ margin: 0 0 8px 0;
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
+}
+
+.page-subtitle {
+ font-size: 14px;
+ color: #B8C8E0;
+ margin: 0;
+}
+
+.header-stats {
+ display: flex;
+ gap: 40px;
+ position: relative;
+ z-index: 1;
+}
+
+.stat-item {
+ text-align: center;
+ padding: 20px;
+ background:
+ linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(147, 51, 234, 0.15) 100%),
+ radial-gradient(circle at center, rgba(255, 255, 255, 0.05), transparent 70%);
+ border-radius: 12px;
+ border: 1px solid rgba(148, 163, 184, 0.2);
+ position: relative;
+ overflow: hidden;
+
+ backdrop-filter: blur(10px);
+}
+
+.stat-item:hover {
+ transform: translateY(-2px) scale(1.05);
+ box-shadow:
+ 0 20px 25px -5px rgba(59, 130, 246, 0.3),
+ 0 10px 10px -5px rgba(59, 130, 246, 0.2);
+}
+
+.stat-item::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -100%;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
+
+}
+
+.stat-item:hover::before {
+ left: 100%;
+}
+
+.stat-label {
+ display: block;
+ font-size: 12px;
+ color: #94A3B8;
+ margin-bottom: 8px;
+ font-weight: 500;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+.stat-value {
+ display: block;
+ font-size: 28px;
+ font-weight: 700;
+ color: #00D4FF;
+ text-shadow:
+ 0 0 20px rgba(0, 212, 255, 0.6),
+ 0 0 40px rgba(0, 212, 255, 0.3);
+ position: relative;
+ z-index: 1;
+}
+
+.stat-value.reduction {
+ color: #00E676;
+ text-shadow:
+ 0 0 20px rgba(0, 230, 118, 0.6),
+ 0 0 40px rgba(0, 230, 118, 0.3);
+}
+
+.dashboard-content {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ min-height: calc(100vh - 200px);
+}
+
+.top-panels {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr;
+ gap: 20px;
+ height: 120px;
+}
+
+.data-panel {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%),
+ radial-gradient(circle at bottom left, rgba(59, 130, 246, 0.08), transparent 50%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 20px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 10px 10px -5px rgba(0, 0, 0, 0.2),
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(16px);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+}
+
+.panel-title {
+ font-size: 12px;
+ color: #94A3B8;
+ margin-bottom: 8px;
+ font-weight: 500;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+.panel-value {
+ font-size: 24px;
+ font-weight: 700;
+ color: #00D4FF;
+ text-shadow:
+ 0 0 20px rgba(0, 212, 255, 0.6),
+ 0 0 40px rgba(0, 212, 255, 0.3);
+ margin-bottom: 4px;
+}
+
+.panel-subtitle {
+ font-size: 11px;
+ color: #B8C8E0;
+ font-weight: 400;
+}
+
+.unit {
+ font-size: 16px;
+ color: #94A3B8;
+}
+
+.center-main-view {
+ display: grid;
+ grid-template-columns: 200px 1fr 300px;
+ gap: 20px;
+ flex: 1;
+}
+
+.left-control-panel {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 20px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(16px);
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.control-section {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.section-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #ffffff;
+ margin-bottom: 8px;
+}
+
+.vertical-radio {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.main-heatmap {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 20px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(16px);
+ display: flex;
+ flex-direction: column;
+}
+
+.heatmap-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ padding-bottom: 15px;
+ border-bottom: 1px solid rgba(148, 163, 184, 0.2);
+}
+
+.main-title {
+ font-size: 18px;
+ font-weight: bold;
+ color: #ffffff;
+ margin: 0;
+}
+
+.date-selector {
+ display: flex;
+ align-items: center;
+}
+
+.heatmap-view {
+ flex: 1;
+}
+
+.right-data-panel {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 20px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(16px);
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.data-section {
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+}
+
+.mini-chart {
+ width: 100%;
+}
+
+.trend-controls {
+ margin-bottom: 10px;
+}
+
+.bottom-progress-panel {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 40px;
+ height: 100px;
+}
+
+.progress-section {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 20px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 0 0 1px rgba(255, 255, 255, 0.05);
+ backdrop-filter: blur(16px);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+.progress-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #ffffff;
+ margin-bottom: 8px;
+}
+
+.progress-data {
+ display: flex;
+ align-items: baseline;
+ gap: 4px;
+ margin-bottom: 12px;
+}
+
+.progress-data .current {
+ font-size: 20px;
+ font-weight: 700;
+ color: #00D4FF;
+}
+
+.progress-data .separator {
+ font-size: 16px;
+ color: #94A3B8;
+}
+
+.progress-data .target {
+ font-size: 14px;
+ color: #B8C8E0;
+}
+
+.bottom-data-table {
+ margin-top: 20px;
+}
+
+.table-panel {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%),
+ radial-gradient(circle at bottom left, rgba(59, 130, 246, 0.08), transparent 50%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 20px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 10px 10px -5px rgba(0, 0, 0, 0.2),
+ 0 0 0 1px rgba(255, 255, 255, 0.05),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ backdrop-filter: blur(16px);
+}
+
+.table-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 15px;
+ padding-bottom: 10px;
+ border-bottom: 1px solid rgba(148, 163, 184, 0.2);
+}
+
+.table-title {
+ font-size: 16px;
+ font-weight: 600;
+ color: #ffffff;
+ margin: 0;
+}
+
+.table-controls {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.panel-card {
+ background:
+ linear-gradient(135deg, rgba(15, 27, 46, 0.9) 0%, rgba(30, 41, 59, 0.85) 100%),
+ radial-gradient(circle at bottom left, rgba(59, 130, 246, 0.08), transparent 50%);
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ border-radius: 16px;
+ padding: 24px;
+ box-shadow:
+ 0 20px 25px -5px rgba(0, 0, 0, 0.3),
+ 0 10px 10px -5px rgba(0, 0, 0, 0.2),
+ 0 0 0 1px rgba(255, 255, 255, 0.05),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+ position: relative;
+ overflow: hidden;
+ backdrop-filter: blur(16px);
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+
+
+.heatmap-card {
+ height: 500px;
+}
+
+.card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ padding-bottom: 15px;
+ border-bottom: 1px solid rgba(81, 129, 219, 0.3);
+ position: relative;
+ z-index: 1;
+}
+
+.card-title {
+ font-size: 18px;
+ font-weight: bold;
+ color: #ffffff;
+ margin: 0;
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
+}
+
+.heatmap-controls {
+ display: flex;
+ align-items: center;
+}
+
+.scope-stats {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ position: relative;
+ z-index: 1;
+}
+
+.scope-item {
+ display: flex;
+ align-items: center;
+ padding: 20px;
+ border-radius: 12px;
+ background:
+ linear-gradient(135deg, rgba(59, 130, 246, 0.12) 0%, rgba(147, 51, 234, 0.12) 100%),
+ radial-gradient(circle at top, rgba(255, 255, 255, 0.05), transparent 60%);
+ border-left: 4px solid #00D4FF;
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ position: relative;
+ overflow: hidden;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ backdrop-filter: blur(8px);
+}
+
+.scope-item:hover {
+ transform: translateY(-3px);
+ box-shadow:
+ 0 15px 30px -5px rgba(59, 130, 246, 0.25),
+ 0 0 0 1px rgba(255, 255, 255, 0.1);
+}
+
+.scope-item::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background: linear-gradient(90deg, #3B82F6, #8B5CF6, #EC4899);
+ opacity: 0;
+ transition: opacity 0.3s ease;
+}
+
+.scope-item:hover::after {
+ opacity: 1;
+}
+
+/* 纰虫帓鏀剧粺璁℃牱寮� */
+.carbon-stats {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ gap: 15px;
+}
+
+.carbon-stat-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 12px;
+ padding: 20px;
+ background:
+ linear-gradient(135deg, rgba(59, 130, 246, 0.12) 0%, rgba(147, 51, 234, 0.12) 100%),
+ radial-gradient(circle at top, rgba(255, 255, 255, 0.05), transparent 60%);
+ border-radius: 12px;
+ border: 1px solid rgba(148, 163, 184, 0.15);
+ flex: 1;
+ position: relative;
+ overflow: hidden;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ backdrop-filter: blur(8px);
+}
+
+.carbon-stat-item:hover {
+ transform: translateY(-3px);
+ box-shadow:
+ 0 15px 30px -5px rgba(59, 130, 246, 0.25),
+ 0 0 0 1px rgba(255, 255, 255, 0.1);
+}
+
+.carbon-stat-item::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 2px;
+ background: linear-gradient(90deg, #3B82F6, #8B5CF6, #EC4899);
+ opacity: 0;
+ transition: opacity 0.3s ease;
+}
+
+.carbon-stat-item:hover::after {
+ opacity: 1;
+}
+
+.carbon-label {
+ color: #94A3B8;
+ font-size: 11px;
+ text-align: center;
+ font-weight: 500;
+ letter-spacing: 0.5px;
+ text-transform: uppercase;
+}
+
+.carbon-value {
+ color: #00D4FF;
+ font-size: 18px;
+ font-weight: 700;
+ text-shadow:
+ 0 0 15px rgba(0, 212, 255, 0.6),
+ 0 0 30px rgba(0, 212, 255, 0.3);
+ position: relative;
+}
+
+.scope-item.scope1 {
+ border-left-color: #FF6B6B;
+}
+
+.scope-item.scope2 {
+ border-left-color: #FFD93D;
+}
+
+.scope-item.scope3 {
+ border-left-color: #6BCF7F;
+}
+
+.scope-icon {
+ font-size: 24px;
+ margin-right: 15px;
+}
+
+.scope-info {
+ flex: 1;
+}
+
+.scope-name {
+ display: block;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 5px;
+}
+
+.scope-value {
+ display: block;
+ font-size: 20px;
+ font-weight: bold;
+ color: #00D4FF;
+ margin-bottom: 3px;
+ text-shadow: 0 0 8px rgba(0, 212, 255, 0.5);
+}
+
+.scope-desc {
+ display: block;
+ font-size: 12px;
+ color: #B8C8E0;
+}
+
+.target-progress {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ position: relative;
+ z-index: 1;
+}
+
+.progress-item {
+ padding: 15px;
+ background: rgba(81, 129, 219, 0.1);
+ border-radius: 8px;
+ border: 1px solid rgba(81, 129, 219, 0.2);
+}
+
+.progress-info {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+}
+
+.progress-label {
+ font-weight: bold;
+ color: #ffffff;
+}
+
+.progress-value {
+ color: #B8C8E0;
+ font-size: 14px;
+}
+
+.bottom-panel {
+ margin-top: 20px;
+}
+
+.table-controls {
+ display: flex;
+ align-items: center;
+}
+
+/* Element Plus 缁勪欢娣辫壊涓婚鏍峰紡 */
+:deep(.el-table) {
+ background: transparent !important;
+ color: #ffffff !important;
+}
+
+:deep(.el-table th) {
+ background: rgba(81, 129, 219, 0.2) !important;
+ color: #ffffff !important;
+ border-bottom: 1px solid rgba(81, 129, 219, 0.3) !important;
+}
+
+:deep(.el-table td) {
+ background: transparent !important;
+ color: #B8C8E0 !important;
+ border-bottom: 1px solid rgba(81, 129, 219, 0.1) !important;
+}
+
+:deep(.el-table tr:hover > td) {
+ background: rgba(81, 129, 219, 0.1) !important;
+}
+
+:deep(.el-input__wrapper) {
+ background: rgba(15, 27, 46, 0.8) !important;
+ border: 1px solid rgba(81, 129, 219, 0.3) !important;
+ color: #ffffff !important;
+}
+
+:deep(.el-input__inner) {
+ color: #ffffff !important;
+}
+
+:deep(.el-button--primary) {
+ background: linear-gradient(135deg, #5181DB, #D369E0) !important;
+ border: none !important;
+ box-shadow: 0 0 10px rgba(81, 129, 219, 0.5) !important;
+}
+
+/* 鍨傜洿鍗曢�夋寜閽粍鏍峰紡 */
+:deep(.vertical-radio) {
+ display: flex !important;
+ flex-direction: column !important;
+ gap: 6px !important;
+}
+
+:deep(.vertical-radio .el-radio-button) {
+ margin: 0 !important;
+ width: 100% !important;
+}
+
+:deep(.vertical-radio .el-radio-button__inner) {
+ background: rgba(59, 130, 246, 0.1) !important;
+ border: 1px solid rgba(148, 163, 184, 0.2) !important;
+ color: #B8C8E0 !important;
+ border-radius: 8px !important;
+ padding: 10px 16px !important;
+ width: 100% !important;
+ text-align: center !important;
+ font-size: 12px !important;
+ font-weight: 500 !important;
+}
+
+:deep(.vertical-radio .el-radio-button__inner:hover) {
+ background: rgba(59, 130, 246, 0.2) !important;
+ border-color: rgba(59, 130, 246, 0.4) !important;
+ color: #ffffff !important;
+}
+
+:deep(.vertical-radio .el-radio-button.is-active .el-radio-button__inner) {
+ background: linear-gradient(135deg, #3B82F6, #8B5CF6) !important;
+ border-color: #3B82F6 !important;
+ color: #ffffff !important;
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3) !important;
+}
+
+:deep(.vertical-radio .el-radio-button:first-child .el-radio-button__inner) {
+ border-left: 1px solid rgba(148, 163, 184, 0.2) !important;
+}
+
+:deep(.el-radio-group .el-radio-button__inner) {
+ background: rgba(59, 130, 246, 0.1) !important;
+ border: 1px solid rgba(148, 163, 184, 0.2) !important;
+ color: #B8C8E0 !important;
+ border-radius: 6px !important;
+ padding: 6px 12px !important;
+ margin: 0 2px !important;
+ font-size: 12px !important;
+}
+
+:deep(.el-radio-group .el-radio-button__inner:hover) {
+ background: rgba(59, 130, 246, 0.2) !important;
+ border-color: rgba(59, 130, 246, 0.4) !important;
+ color: #ffffff !important;
+}
+
+:deep(.el-radio-group .el-radio-button.is-active .el-radio-button__inner) {
+ background: linear-gradient(135deg, #3B82F6, #8B5CF6) !important;
+ border-color: #3B82F6 !important;
+ color: #ffffff !important;
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3) !important;
+}
+
+:deep(.el-date-editor .el-input__wrapper) {
+ background: rgba(15, 27, 46, 0.8) !important;
+ border: 1px solid rgba(81, 129, 219, 0.3) !important;
+}
+
+:deep(.el-progress-bar__outer) {
+ background: rgba(81, 129, 219, 0.2) !important;
+}
+
+:deep(.el-tag) {
+ background: rgba(81, 129, 219, 0.2) !important;
+ border: 1px solid rgba(81, 129, 219, 0.3) !important;
+ color: #ffffff !important;
+}
+
+:deep(.el-tag.el-tag--success) {
+ background: rgba(0, 230, 118, 0.2) !important;
+ border-color: rgba(0, 230, 118, 0.3) !important;
+ color: #00E676 !important;
+}
+
+:deep(.el-tag.el-tag--warning) {
+ background: rgba(255, 193, 7, 0.2) !important;
+ border-color: rgba(255, 193, 7, 0.3) !important;
+ color: #FFC107 !important;
+}
+
+:deep(.el-tag.el-tag--danger) {
+ background: rgba(244, 67, 54, 0.2) !important;
+ border-color: rgba(244, 67, 54, 0.3) !important;
+ color: #F44336 !important;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 1200px) {
+ .main-content {
+ flex-direction: column;
+ }
+
+ .header-stats {
+ gap: 20px;
+ }
+}
+
+@media (max-width: 768px) {
+ .page-header {
+ flex-direction: column;
+ text-align: center;
+ gap: 20px;
+ }
+
+ .header-stats {
+ justify-content: center;
+ }
+
+ .carbon-management {
+ padding: 10px;
+ }
+}
+</style>
\ No newline at end of file
--
Gitblit v1.9.3