154 lines
3.5 KiB
Vue
154 lines
3.5 KiB
Vue
<script setup>
|
|
import { ref, onMounted, watch, inject } from "vue";
|
|
import * as echarts from "echarts";
|
|
import { getRealTimeDist } from "@/apis/energy";
|
|
import { useI18n } from "vue-i18n";
|
|
const { search_data } = inject("energy_data");
|
|
const { t } = useI18n();
|
|
|
|
const chartDiv = ref(null);
|
|
let myChart = null; // 添加 myChart 变量
|
|
|
|
const chartOption = {
|
|
tooltip: {
|
|
trigger: "item",
|
|
formatter: (p) => {
|
|
return `${p.name}: ${p.value}kWh (${p.data.percentage}%)`;
|
|
},
|
|
},
|
|
series: [
|
|
{
|
|
type: "sankey",
|
|
layout: "none",
|
|
nodeWidth: 10,
|
|
nodeGap: 10,
|
|
right: 180,
|
|
data: [],
|
|
links: [],
|
|
emphasis: {
|
|
focus: "adjacency",
|
|
},
|
|
label: {
|
|
position: "right",
|
|
fontSize: 14,
|
|
color: "#fff",
|
|
formatter: (p) => {
|
|
return `${p.name} (${p.data.percentage}%)`;
|
|
},
|
|
},
|
|
itemStyle: {
|
|
borderWidth: 0,
|
|
},
|
|
lineStyle: {
|
|
color: "gradient",
|
|
opacity: 0.7,
|
|
curveness: 0.5,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const loadData = async (value) => {
|
|
const res = await getRealTimeDist(value);
|
|
if (res.isSuccess && res.data && res.data.length !== 0) {
|
|
const rawData = res.data;
|
|
if (rawData) {
|
|
const totalValue = rawData.reduce((acc, item) => acc + item.value, 0);
|
|
|
|
const sortedData = [...rawData].sort((a, b) => b.value - a.value);
|
|
// 構造 data 節點
|
|
const data = [
|
|
{ name: "Total", value: totalValue, percentage: 100 },
|
|
...sortedData.map((item) => ({
|
|
name: item.key,
|
|
value: item.value,
|
|
percentage: item.percentage,
|
|
})),
|
|
];
|
|
|
|
// 構造 links 連結
|
|
const links = sortedData.map((item, index) => ({
|
|
source: "Total",
|
|
target: item.key,
|
|
value: item.value,
|
|
percentage: item.percentage,
|
|
}));
|
|
|
|
const colors = [
|
|
"#45f4ef",
|
|
"#17CEE3",
|
|
"#E4EA00",
|
|
"#62E39A",
|
|
"#E9971F",
|
|
"#E52EFF",
|
|
];
|
|
// 更新 chartOption
|
|
chartOption.series[0].data = data.map((item, index) => ({
|
|
...item,
|
|
itemStyle: {
|
|
color: colors[index % colors.length], // 節點顏色
|
|
},
|
|
}));
|
|
chartOption.series[0].links = links;
|
|
|
|
// 初始化圖表
|
|
if (myChart) {
|
|
myChart.dispose(); // 銷毀之前的實例
|
|
}
|
|
myChart = echarts.init(chartDiv.value);
|
|
myChart.setOption(chartOption);
|
|
}
|
|
} else {
|
|
// 清空圖表
|
|
if (myChart) {
|
|
myChart.dispose(); // 銷毀之前的實例
|
|
myChart = null;
|
|
}
|
|
}
|
|
};
|
|
|
|
watch(
|
|
search_data,
|
|
(newValue, oldValue) => {
|
|
if (
|
|
newValue.building_guid &&
|
|
JSON.stringify(newValue) !== JSON.stringify(oldValue)
|
|
) {
|
|
loadData(newValue);
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
deep: true,
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
// 初始化圖表
|
|
myChart = echarts.init(chartDiv.value);
|
|
myChart.setOption(chartOption);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="p-3">
|
|
<h2 class="text text-lg text-white mb-5 relative">
|
|
{{ $t("energy.elec_consumption") }}
|
|
</h2>
|
|
<div class="chart-container">
|
|
<div ref="chartDiv" class="w-full min-h-[200px] h-full"></div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.text::after {
|
|
@apply absolute -bottom-2.5 left-0 block w-3/5 h-[1px] bg-slate-600;
|
|
content: "";
|
|
}
|
|
|
|
ul li:last-child:after {
|
|
@apply absolute top-0 bottom-0 left-full block w-full h-[1px] bg-slate-600 m-auto z-10;
|
|
content: "";
|
|
}
|
|
</style> |