209 lines
5.1 KiB
Vue
209 lines
5.1 KiB
Vue
<script setup>
|
|
import { ref, onMounted, watch, onUnmounted } from "vue";
|
|
import * as echarts from "echarts";
|
|
import { getSystemEnergyCostTrend } from "@/apis/headquarters";
|
|
import BarChart from "@/components/chart/BarChart.vue";
|
|
import { useI18n } from "vue-i18n";
|
|
import dayjs from "dayjs";
|
|
import useBuildingStore from "@/stores/useBuildingStore";
|
|
|
|
const storeBuild = useBuildingStore();
|
|
const { t } = useI18n();
|
|
|
|
const chartData = ref([]);
|
|
const buildingList = ref([]);
|
|
const energyCostData = ref([]);
|
|
const weekComparisonOption = ref({});
|
|
const currentType = ref({});
|
|
let intervalId = null;
|
|
// 生成柱狀圖的 option
|
|
const generateCylinderChartOption = (data) => {
|
|
const barWidth = 15;
|
|
return {
|
|
xAxis: {
|
|
type: "category",
|
|
data: data.map((item) => item.date),
|
|
axisLine: {
|
|
lineStyle: {
|
|
color: "#fff",
|
|
},
|
|
},
|
|
},
|
|
yAxis: {
|
|
type: "value",
|
|
name: "kWh",
|
|
axisLine: {
|
|
lineStyle: {
|
|
color: "#fff",
|
|
},
|
|
},
|
|
splitLine: {
|
|
show: false,
|
|
},
|
|
},
|
|
series: [
|
|
{
|
|
data: data.map((item) => item.energy),
|
|
type: "bar",
|
|
barWidth: barWidth,
|
|
itemStyle: {
|
|
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
|
{ offset: 0, color: "#1F7B47" },
|
|
{ offset: 1, color: "#247E95" },
|
|
]),
|
|
shadowBlur: 5,
|
|
shadowColor: "rgba(0, 0, 0, 0.5)",
|
|
shadowOffsetY: 5,
|
|
},
|
|
},
|
|
{
|
|
z: 15,
|
|
type: "pictorialBar",
|
|
symbolPosition: "end",
|
|
data: data.map((item) => item.energy),
|
|
symbol: "diamond",
|
|
symbolOffset: [0, -5],
|
|
symbolSize: [barWidth, barWidth * 0.5],
|
|
itemStyle: {
|
|
color: "#62E39A",
|
|
},
|
|
},
|
|
{
|
|
z: 10,
|
|
type: "pictorialBar",
|
|
data: data.map((item) => item.energy),
|
|
symbol: "diamond",
|
|
symbolSize: [barWidth, barWidth * 0.5],
|
|
symbolOffset: [0, 6],
|
|
itemStyle: {
|
|
color: "#247E95",
|
|
},
|
|
},
|
|
],
|
|
grid: {
|
|
left: "0%",
|
|
right: "0%",
|
|
bottom: "0%",
|
|
top: "16%",
|
|
containLabel: true,
|
|
},
|
|
tooltip: {
|
|
trigger: "axis",
|
|
formatter: function (params) {
|
|
const item = params[0];
|
|
return `<p>${item.name}</p> <p>${item.marker}Energy consumption : ${item.value}</p>`;
|
|
},
|
|
},
|
|
};
|
|
};
|
|
|
|
const processEnergyData = async () => {
|
|
try {
|
|
const res = await getSystemEnergyCostTrend({
|
|
building_id: currentType.value.name,
|
|
});
|
|
energyCostData.value = res.data.trend || [];
|
|
if (!energyCostData.value || energyCostData.value.length === 0) {
|
|
chartData.value = [];
|
|
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
|
return;
|
|
}
|
|
const dailyData = [...energyCostData.value].sort(
|
|
(a, b) => new Date(a.time) - new Date(b.time)
|
|
);
|
|
chartData.value = dailyData.map((item) => ({
|
|
date: dayjs(item.time).format("MM/DD"),
|
|
energy: item.value,
|
|
}));
|
|
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
|
} catch (error) {
|
|
console.error("Error fetching energy cost trend:", error);
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => storeBuild.buildings,
|
|
(newValue) => {
|
|
if (newValue) {
|
|
currentType.value = {
|
|
name: newValue[0]?.building_guid || "all",
|
|
};
|
|
buildingList.value = [
|
|
...newValue.map((building) => ({
|
|
title: building.full_name,
|
|
key: building.building_guid,
|
|
})),
|
|
];
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
}
|
|
);
|
|
|
|
// 監聽 currentType 變化時重新取得資料
|
|
watch(
|
|
() => currentType.value.name,
|
|
(newValue) => {
|
|
if (newValue) {
|
|
processEnergyData();
|
|
if (intervalId) {
|
|
clearInterval(intervalId);
|
|
}
|
|
intervalId = setInterval(() => {
|
|
processEnergyData();
|
|
}, 60 * 60 * 1000);
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
}
|
|
);
|
|
|
|
onUnmounted(() => {
|
|
clearInterval(intervalId);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="w-full chart-data relative px-3">
|
|
<div class="flex flex-wrap items-center justify-between">
|
|
<h2 class="font-light pt-1 px-1">
|
|
{{ $t("dashboard.last_30_days_energy_trend") }}
|
|
</h2>
|
|
<Select
|
|
:value="currentType"
|
|
class="w-[8.5rem] my-2"
|
|
selectClass="border-info focus-within:border-info btn-xs text-xs"
|
|
name="name"
|
|
Attribute="title"
|
|
:options="buildingList"
|
|
:isTopLabelExist="false"
|
|
:isBottomLabelExist="false"
|
|
>
|
|
</Select>
|
|
</div>
|
|
<div class="h-[200px]">
|
|
<BarChart
|
|
id="dashboard_chart_week_comparison"
|
|
class="h-full"
|
|
:option="weekComparisonOption"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.chart-data:before {
|
|
@apply absolute -left-0 -top-1 h-10 w-10 bg-no-repeat z-10;
|
|
content: "";
|
|
background: url(@ASSET/img/chart-data-background01.svg) center center;
|
|
}
|
|
|
|
.chart-data::after {
|
|
@apply absolute -right-1 bottom-1 h-10 w-10 bg-no-repeat z-10;
|
|
content: "";
|
|
background: url(@ASSET/img/chart-data-background02.svg) center center;
|
|
}
|
|
</style>
|