Files
admin-vben5/apps/web-antd/src/views/property/energyManagement/electricEnergy/elctricitySituation/index.vue

517 lines
11 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { RadioGroup, RadioButton, message } from 'ant-design-vue';
import { Page } from '@vben/common-ui';
import { ref, onMounted, onBeforeUnmount, reactive } from 'vue';
import * as echarts from 'echarts';
import type { ECharts, EChartsOption } from 'echarts';
import FloorTree from '../components/floor-tree.vue';
import dayjs from 'dayjs';
import { meterRecordTrend } from '#/api/property/energyManagement/meterRecord';
// 左边楼层用
const selectFloorId = ref<string[]>([]);
const chainData = reactive({
todayEnergy: '231.78',
yesterdaySamePeriodEnergy: '269.56',
dayTrendPercentage: '-14.02%',
dayTrendValue: '-37.78',
currentMonthEnergy: '18758.39',
lastMonthSamePeriodEnergy: '--',
monthTrendPercentage: '--',
monthTrendValue: '--',
currentYearEnergy: '18758.39',
lastYearSamePeriodEnergy: '--',
yearTrendPercentage: '--',
yearTrendValue: '--',
});
const peakData = reactive({
todayPeakPower: '2961.08',
todayPeakTime: dayjs().format('YYYY-MM-DD HH:mm:ss'),
yesterdayPeakPower: '2993.89',
yesterdayPeakTime: dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'),
});
const energyTrendTime = ref('1');
// 能耗趋势图表容器
const energyTrendChart = ref<HTMLElement | null>(null);
const energyTrendInstance = ref<ECharts | null>(null);
const energyTrendOption: EChartsOption = {
tooltip: {
trigger: 'item',
axisPointer: {
type: 'shadow',
},
},
xAxis: {
type: 'category',
data: [],
name: '时间',
},
yAxis: {
type: 'value',
name: 'kW.h',
},
series: [
{
data: [],
type: 'bar',
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' },
],
},
},
],
};
const initEnergyTrendChart = () => {
if (energyTrendChart.value) {
// 销毁旧实例
energyTrendInstance.value?.dispose();
// 创建新实例
energyTrendInstance.value = echarts.init(energyTrendChart.value);
// 设置配置项
energyTrendInstance.value.setOption(energyTrendOption);
// buildingEnergyTrendData('1');
// 可选:添加窗口大小变化监听
const resizeHandler = () => {
energyTrendInstance.value?.resize();
};
window.addEventListener('resize', resizeHandler);
// 在组件卸载前移除监听
onBeforeUnmount(() => {
window.removeEventListener('resize', resizeHandler);
});
}
};
function buildingEnergyTrendData(val: string) {
if (trendData.value.hour == null) {
message.warning('请先选择楼层或电表!');
return;
}
const now = new Date();
let timeArr = [];
let valArr = [];
let name = '时间';
if (val == '1') {
const hour = now.getHours();
for (let i = 0; i < hour; i++) {
timeArr.push(i + ':00');
}
valArr = trendData.value.hour.today.data;
} else if (val == '2') {
const day = now.getDate();
for (let i = 1; i < day; i++) {
timeArr.push(i);
}
name = '日期';
valArr = trendData.value.day.nowMonth.data;
} else {
const month = now.getMonth() + 1;
for (let i = 1; i < month + 1; i++) {
timeArr.push(i);
}
name = '月份';
valArr = trendData.value.month.nowYear.data;
}
if (energyTrendInstance.value) {
energyTrendInstance.value.setOption({
xAxis: { data: timeArr, name },
series: [{ data: valArr }],
});
}
}
//日用电率
const powerCurveChart = ref<HTMLElement | null>(null);
const powerCurveInstance = ref<ECharts | null>(null);
const powerCurveOption: EChartsOption = {
tooltip: {
trigger: 'item',
axisPointer: {
type: 'cross',
crossStyle: {
color: '#999',
},
},
},
toolbox: {
feature: {
magicType: { show: true, type: ['line', 'bar'] },
restore: { show: true },
},
},
legend: {
data: ['今日', '昨日'],
},
xAxis: [
{
type: 'category',
data: [
'0:00',
'1:00',
'2:00',
'3:00',
'4:00',
'5:00',
'6:00',
'7:00',
'8:00',
'9:00',
'10:00',
'11:00',
'12:00',
'13:00',
'14:00',
'15:00',
'16:00',
'17:00',
'18:00',
'19:00',
'20:00',
'21:00',
'22:00',
'23:00',
],
axisPointer: {
type: 'shadow',
},
name: '时',
},
],
yAxis: [
{
type: 'value',
name: 'kW',
},
],
series: [
{
name: '昨日',
type: 'line',
smooth: true,
data: [],
markPoint: {
data: [{ type: 'max' }, { type: 'min' }],
},
itemStyle: { color: '#cbb0e3' }, // 数据点颜色
lineStyle: { color: '#cbb0e3' }, // 线条颜色
},
],
};
const initPowerCurveChart = () => {
if (powerCurveChart.value) {
// 销毁旧实例
powerCurveInstance.value?.dispose();
// 创建新实例
powerCurveInstance.value = echarts.init(powerCurveChart.value);
// 设置配置项
powerCurveInstance.value.setOption(powerCurveOption);
// 可选:添加窗口大小变化监听
const resizeHandler = () => {
powerCurveInstance.value?.resize();
};
window.addEventListener('resize', resizeHandler);
// 在组件卸载前移除监听
onBeforeUnmount(() => {
window.removeEventListener('resize', resizeHandler);
});
}
};
// 组件挂载后初始化图表
onMounted(() => {
initEnergyTrendChart();
initPowerCurveChart();
});
// 组件卸载前销毁图表实例
onBeforeUnmount(() => {
energyTrendInstance.value?.dispose();
powerCurveInstance.value?.dispose();
});
const trendData = ref<any>({});
async function handleSelectFloor(selectedKeys, info) {
const now = new Date();
// 获取年、月、日
const year = now.getFullYear();
// 月份从0开始所以要+1并格式化为两位数
const month = String(now.getMonth() + 1).padStart(2, '0');
// 日期格式化为两位数
const day = String(now.getDate()).padStart(2, '0');
let data = {
day: year + '-' + month + '-' + day,
month: year + '-' + month,
year: year,
meterType: 1,
meterId: null,
floorId: null,
};
if (info.node.level == 3) {
data.floorId = selectedKeys[0];
} else {
data.meterId = selectedKeys[0];
}
const trend = await meterRecordTrend(data);
trendData.value = trend;
// 趋势曲线
let timeArr = [];
let valArr = [];
let name = '时间';
if (energyTrendTime.value == '1') {
const hour = now.getHours();
for (let i = 0; i < hour; i++) {
timeArr.push(i + ':00');
}
valArr = trend.hour.today.data;
} else if (energyTrendTime.value == '2') {
const day = now.getDate();
for (let i = 1; i < day; i++) {
timeArr.push(i);
}
name = '日期';
valArr = trend.day.nowMonth.data;
} else {
const month = now.getMonth() + 1;
for (let i = 1; i < month + 1; i++) {
timeArr.push(i);
}
name = '月份';
valArr = trend.month.nowYear.data;
}
if (energyTrendInstance.value) {
energyTrendInstance.value.setOption({
xAxis: { data: timeArr, name },
series: [{ data: valArr }],
});
}
if (powerCurveInstance.value) {
powerCurveInstance.value.setOption({
series: [
{
name: '今日',
type: 'line',
smooth: true,
data: trend.hour.today.data,
markPoint: {
data: [{ type: 'max' }, { type: 'min' }],
},
},
{
name: '昨日',
type: 'line',
smooth: true,
data: trend.hour.yesterday.data,
markPoint: {
data: [{ type: 'max' }, { type: 'min' }],
},
},
],
});
}
}
</script>
<template>
<Page :auto-content-height="true">
<div class="flex h-full gap-[8px]">
<FloorTree class="w-[260px]" @select="handleSelectFloor"></FloorTree>
<div class="flex-1 overflow-hidden">
<div class="row">
<div class="energy-trend-container">
<div class="energy-trend-top">
<div class="section-header">
<div class="header-title">能耗趋势</div>
</div>
<RadioGroup
v-model:value="energyTrendTime"
button-style="solid"
size="small"
@change="buildingEnergyTrendData(energyTrendTime)"
>
<RadioButton value="1">当日</RadioButton>
<RadioButton value="2">当月</RadioButton>
<RadioButton value="3">当年</RadioButton>
</RadioGroup>
</div>
<div class="chart-placeholder" ref="energyTrendChart"></div>
</div>
</div>
<div class="row">
<div class="power-curve-container">
<div class="section-header">
<div class="header-title">平均电功率曲线</div>
</div>
<div class="power-chart" ref="powerCurveChart"></div>
</div>
<!-- <div class="power-peak-container">
<div class="section-header">
<div class="header-title">电功率峰值</div>
</div>
<div class="peak-item">
<p class="value">{{ peakData.todayPeakPower }}</p>
<p class="time">{{ peakData.todayPeakTime }}</p>
<div class="bottom-text">当日(kW)</div>
</div>
<div class="peak-item">
<p class="value">{{ peakData.yesterdayPeakPower }}</p>
<p class="time">{{ peakData.yesterdayPeakTime }}</p>
<div class="bottom-text">昨日(kW)</div>
</div>
</div> -->
</div>
</div>
</div>
</Page>
</template>
<style scoped>
.row {
display: flex;
gap: 1rem;
width: 100%;
}
.comparison-section-container {
flex: 2;
}
.energy-trend-container {
flex: 3;
}
.power-curve-container {
margin-top: 10px;
flex: 5;
}
.power-peak-container {
margin-top: 10px;
flex: 1;
}
.energy-trend-top {
display: flex;
justify-content: space-between;
}
.section-header {
border-left: 4px solid #3671e8;
margin-bottom: 15px;
padding-left: 16px;
}
.header-title {
font-size: 16px;
color: #333;
}
.comparison-section-container,
.energy-trend-container,
.power-curve-container,
.power-peak-container {
background: #fff;
border-radius: 5px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 1rem;
}
.comparison-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 5px;
}
.comparison-item {
padding: 5px 10px;
border: 1px solid #e0e0e0;
text-align: center;
}
.item-value {
font-size: 22px;
color: #333;
margin-bottom: 10px;
}
.item-title {
font-size: 12px;
color: #666;
}
.item-top {
font-size: 16px;
margin-bottom: 10px;
}
.item-percent {
color: #7fb926;
margin-bottom: 5px;
border-bottom: 1px solid #666;
}
.item-unit {
font-size: 12px;
color: #999;
margin-left: 3px;
}
.chart-placeholder {
height: 36vh;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.power-chart {
height: 38vh;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.peak-item {
padding: 15px 0 0 0;
border: 1px solid #3671e8;
text-align: center;
margin-bottom: 1rem;
.bottom-text {
background-color: #3671e8;
color: white;
line-height: 40px;
}
}
.peak-item .value {
font-size: 22px;
color: #333;
}
.peak-item .time {
font-size: 12px;
color: #999;
margin: 5px 0;
}
</style>