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.
354 lines
12 KiB
354 lines
12 KiB
<template>
|
|
<div class="shore-power-usage">
|
|
<!-- Average Mode -->
|
|
<template v-if="displayMode === 'average'">
|
|
<div class="left" style="width: 40%;">
|
|
<div v-for="card in cards.slice(0, 3)" :key="card.id" class="card digital-twin-card--deep-blue"
|
|
@click="handleSelectCard(card.id)">
|
|
<div class="card-title">
|
|
<div class="vertical-line"></div>
|
|
<img src="@/assets/svgs/data.svg" class="title-icon" />
|
|
<span class="title-text">{{ card.title }}</span>
|
|
</div>
|
|
<div class="card-content">
|
|
<div v-if="card.type === 'overview'" class="overview-grid">
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ totalPower }}</div>
|
|
<div class="overview-label">累计用电(千瓦时)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ fuelReduction }}</div>
|
|
<div class="overview-label">减少燃油(吨)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ co2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化碳排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ pm25Reduction }}</div>
|
|
<div class="overview-label">减少PM2.5排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ noxReduction }}</div>
|
|
<div class="overview-label">减少氮氧化物(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ so2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化硫(千克)</div>
|
|
</div>
|
|
</div>
|
|
<BarChartMinute v-else :chart-data="commonChartData" :title="card.title" :color="card.color" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="right" style="width: 40%;">
|
|
<div v-for="card in cards.slice(3)" :key="card.id" class="card digital-twin-card--deep-blue"
|
|
@click="handleSelectCard(card.id)">
|
|
<div class="card-title">
|
|
<div class="vertical-line"></div>
|
|
<img src="@/assets/svgs/data.svg" class="title-icon" />
|
|
<span class="title-text">{{ card.title }}</span>
|
|
</div>
|
|
<div class="card-content">
|
|
<div v-if="card.type === 'overview'" class="overview-grid">
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ totalPower }}</div>
|
|
<div class="overview-label">累计用电(千瓦时)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ fuelReduction }}</div>
|
|
<div class="overview-label">减少燃油(吨)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ co2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化碳排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ pm25Reduction }}</div>
|
|
<div class="overview-label">减少PM2.5排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ noxReduction }}</div>
|
|
<div class="overview-label">减少氮氧化物(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ so2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化硫(千克)</div>
|
|
</div>
|
|
</div>
|
|
<BarChartMinute v-else :chart-data="commonChartData" :title="card.title" :color="card.color" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- Magnify Mode -->
|
|
<div v-if="displayMode === 'magnify'" class="magnify">
|
|
<div class="big">
|
|
<div v-for="card in cards.filter(c => c.id === selectedCard)" :key="card.id"
|
|
class="card digital-twin-card--deep-blue" @click="handleSelectCard(card.id)">
|
|
<div class="card-title">
|
|
<div class="vertical-line"></div>
|
|
<img src="@/assets/svgs/data.svg" class="title-icon" />
|
|
<span class="title-text">{{ card.title }}</span>
|
|
</div>
|
|
<div class="card-content">
|
|
<div v-if="card.type === 'overview'" class="overview-grid">
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ totalPower }}</div>
|
|
<div class="overview-label">累计用电(千瓦时)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ fuelReduction }}</div>
|
|
<div class="overview-label">减少燃油(吨)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ co2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化碳排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ pm25Reduction }}</div>
|
|
<div class="overview-label">减少PM2.5排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ noxReduction }}</div>
|
|
<div class="overview-label">减少氮氧化物(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ so2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化硫(千克)</div>
|
|
</div>
|
|
</div>
|
|
<BarChartMinute v-else :chart-data="commonChartData" :title="card.title" :color="card.color" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="one-row">
|
|
<div v-for="card in cards.filter(c => c.id !== selectedCard)" :key="card.id"
|
|
class="card digital-twin-card--deep-blue" @click="handleSelectCard(card.id)">
|
|
<div class="card-title">
|
|
<div class="vertical-line"></div>
|
|
<img src="@/assets/svgs/data.svg" class="title-icon" />
|
|
<span class="title-text">{{ card.title }}</span>
|
|
</div>
|
|
<div class="card-content">
|
|
<div v-if="card.type === 'overview'" class="overview-grid">
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ totalPower }}</div>
|
|
<div class="overview-label">累计用电(千瓦时)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ fuelReduction }}</div>
|
|
<div class="overview-label">减少燃油(吨)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ co2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化碳排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ pm25Reduction }}</div>
|
|
<div class="overview-label">减少PM2.5排放(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ noxReduction }}</div>
|
|
<div class="overview-label">减少氮氧化物(千克)</div>
|
|
</div>
|
|
<div class="overview-item">
|
|
<div class="overview-value">{{ so2Reduction }}</div>
|
|
<div class="overview-label">减少二氧化硫(千克)</div>
|
|
</div>
|
|
</div>
|
|
<BarChartMinute v-else :chart-data="commonChartData" :title="card.title" :color="card.color" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
|
import BarChartMinute from './charts/BarChartMinute.vue'
|
|
|
|
// 定义组件属性
|
|
interface ChartDataItem {
|
|
name: string;
|
|
value: number;
|
|
}
|
|
|
|
interface CardInfo {
|
|
id: string;
|
|
title: string;
|
|
type: 'overview' | 'chart';
|
|
unit?: string;
|
|
color?: string;
|
|
}
|
|
|
|
interface Props {
|
|
totalPower: number;
|
|
fuelReduction: number;
|
|
co2Reduction: number;
|
|
pm25Reduction: number;
|
|
noxReduction: number;
|
|
so2Reduction: number;
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
const displayMode = ref<'average' | 'magnify'>('average')
|
|
const selectedCard = ref<string>('overview')
|
|
// 创建统一的模拟数据源
|
|
const commonChartData = ref<ChartDataItem[]>([])
|
|
|
|
// 定义卡片信息
|
|
const cards = ref<CardInfo[]>([
|
|
{
|
|
id: 'overview',
|
|
title: '总览',
|
|
type: 'overview'
|
|
},
|
|
{
|
|
id: 'fuel',
|
|
title: '减少燃油(吨)',
|
|
type: 'chart',
|
|
unit: '吨',
|
|
color: '#4CAF50' // 绿色 - 代表节能、清洁能源
|
|
},
|
|
{
|
|
id: 'co2',
|
|
title: '减少CO₂排放(千克)',
|
|
type: 'chart',
|
|
unit: '千克',
|
|
color: '#2E7D32' // 深绿色/蓝绿 - 温室气体(国际常用低碳绿色系)
|
|
},
|
|
{
|
|
id: 'pm25',
|
|
title: '减少PM2.5排放(千克)',
|
|
type: 'chart',
|
|
unit: '千克',
|
|
color: '#9E9E9E' // 灰色 - 颗粒物(国际通用)
|
|
},
|
|
{
|
|
id: 'nox',
|
|
title: '减少NOₓ排放(千克)',
|
|
type: 'chart',
|
|
unit: '千克',
|
|
color: '#FF9800' // 橙色 - 氮氧化物(国际通用)
|
|
},
|
|
{
|
|
id: 'so2',
|
|
title: '减少SO₂排放(千克)',
|
|
type: 'chart',
|
|
unit: '千克',
|
|
color: '#FFEB3B' // 黄色 - 二氧化硫(国际通用)
|
|
}
|
|
])
|
|
|
|
const handleSelectCard = (cardId: string) => {
|
|
// 如果当前已经是放大模式且点击的是当前选中的大卡片,则返回平均模式
|
|
if (displayMode.value === 'magnify' && selectedCard.value === cardId) {
|
|
displayMode.value = 'average'
|
|
} else {
|
|
// 否则进入放大模式并选中指定卡片
|
|
displayMode.value = 'magnify'
|
|
selectedCard.value = cardId
|
|
}
|
|
}
|
|
// 生成初始数据
|
|
const generateInitialData = () => {
|
|
const now = new Date()
|
|
const data: ChartDataItem[] = []
|
|
|
|
// 生成过去5分钟的数据,每10秒一条
|
|
for (let i = 29; i >= 0; i--) {
|
|
const time = new Date(now.getTime() - i * 10000)
|
|
data.push({
|
|
name: time.toLocaleTimeString(),
|
|
value: Math.floor(Math.random() * 100) + 10
|
|
})
|
|
}
|
|
|
|
return data
|
|
}
|
|
|
|
// 定时器引用
|
|
let timer: number | null = null
|
|
|
|
// 追加新数据
|
|
const appendNewData = () => {
|
|
const now = new Date()
|
|
commonChartData.value.push({
|
|
name: now.toLocaleTimeString(),
|
|
value: Math.floor(Math.random() * 100) + 10
|
|
})
|
|
}
|
|
|
|
// 组件挂载时初始化数据和定时器
|
|
onMounted(() => {
|
|
commonChartData.value = generateInitialData()
|
|
timer = window.setInterval(appendNewData, 1000)
|
|
})
|
|
|
|
// 组件销毁前清除定时器
|
|
onBeforeUnmount(() => {
|
|
if (timer) {
|
|
window.clearInterval(timer)
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.shore-power-usage {
|
|
display: flex;
|
|
height: 100%;
|
|
gap: 10px;
|
|
}
|
|
|
|
.magnify {
|
|
width: 100%;
|
|
padding: 12px;
|
|
height: calc(100vh - 72px);
|
|
position: absolute;
|
|
top: 72px;
|
|
left: 0px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
/* background-color: red; */
|
|
gap: 8px;
|
|
overflow-y: auto;
|
|
|
|
.big {
|
|
height: 70%;
|
|
|
|
.card {
|
|
height: 100%;
|
|
}
|
|
|
|
.overview-value {
|
|
font-size: 32px;
|
|
}
|
|
|
|
.overview-label {
|
|
font-size: 24px;
|
|
}
|
|
}
|
|
|
|
.one-row {
|
|
height: 30%;
|
|
display: flex;
|
|
gap: 8px;
|
|
|
|
.card {
|
|
flex: 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
.card {
|
|
padding: 6px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.right {
|
|
/* gap: 0 */
|
|
}
|
|
</style>
|