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

<template>
<div class="shore-power-usage">
1 month ago
<!-- 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>
1 month ago
<BarChartMinute v-else :chart-data="commonChartData" :title="card.title" :color="card.color" />
</div>
</div>
</div>
1 month ago
<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>
1 month ago
</template>
1 month ago
<!-- 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>
1 month ago
<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">
1 month ago
import { ref, onMounted, onBeforeUnmount } from 'vue'
import BarChartMinute from './charts/BarChartMinute.vue'
// 定义组件属性
interface ChartDataItem {
name: string;
value: number;
}
1 month ago
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;
}
1 month ago
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>
1 month ago
<style lang="scss" scoped>
.shore-power-usage {
display: flex;
height: 100%;
gap: 10px;
}
1 month ago
.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>