248 lines
5.4 KiB
Vue
248 lines
5.4 KiB
Vue
<script setup>
|
|
import { ref, onMounted, watch } from "vue";
|
|
import * as echarts from "echarts";
|
|
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 props = defineProps({
|
|
formState: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
energyCostData: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
getEnergyCostData: {
|
|
type: Function,
|
|
required: true,
|
|
}
|
|
});
|
|
|
|
|
|
const chartData = ref([]);
|
|
const floorList = ref([]);
|
|
const deptList = ref([]);
|
|
const weekComparisonOption = ref({});
|
|
|
|
// 生成柱狀圖的 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: "3%",
|
|
top: "15%",
|
|
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 = () => {
|
|
if (!props.energyCostData || !props.energyCostData.trend) {
|
|
chartData.value = [];
|
|
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
|
return;
|
|
}
|
|
|
|
const dailyData = props.energyCostData.trend;
|
|
|
|
chartData.value = dailyData.map((item) => ({
|
|
date: dayjs(item.time).format("MM/DD"),
|
|
energy: item.value,
|
|
}));
|
|
|
|
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
|
};
|
|
|
|
watch(
|
|
() => props.energyCostData,
|
|
(newEnergyCostData) => {
|
|
processEnergyData();
|
|
},
|
|
{ deep: true, immediate: true }
|
|
);
|
|
|
|
watch(
|
|
() => storeBuild.floorList,
|
|
(newValue) => {
|
|
if (newValue) {
|
|
console.log('newValue',newValue);
|
|
|
|
floorList.value = [
|
|
{
|
|
title: "All",
|
|
key: "all",
|
|
},
|
|
...storeBuild.floorList,
|
|
];
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => storeBuild.floorList,
|
|
(newValue) => {
|
|
if (newValue) {
|
|
floorList.value = [
|
|
{
|
|
title: "All",
|
|
key: "all",
|
|
},
|
|
...storeBuild.floorList,
|
|
];
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
}
|
|
);
|
|
|
|
watch(
|
|
() => storeBuild.deptList,
|
|
(newValue) => {
|
|
if (newValue) {
|
|
deptList.value = [
|
|
{
|
|
title: "All",
|
|
key: "all",
|
|
},
|
|
...storeBuild.deptList,
|
|
];
|
|
}
|
|
},
|
|
{
|
|
deep: true,
|
|
immediate: true,
|
|
}
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<div class="w-full chart-data relative px-8 py-1">
|
|
<div class="flex flex-wrap items-center justify-between">
|
|
<h2 class="font-light">{{ $t("dashboard.last_30_days_energy_trend") }}</h2>
|
|
<div class="flex items-center w-52 gap-4">
|
|
<Select
|
|
:value="props.formState"
|
|
class="my-2"
|
|
selectClass="border-info focus-within:border-info btn-xs text-xs"
|
|
name="floor_guid"
|
|
Attribute="title"
|
|
:options="floorList"
|
|
:isTopLabelExist="false"
|
|
:isBottomLabelExist="false"
|
|
>
|
|
</Select>
|
|
<Select
|
|
:value="props.formState"
|
|
class="my-2"
|
|
selectClass="border-info focus-within:border-info btn-xs text-xs"
|
|
name="department_id"
|
|
Attribute="title"
|
|
:options="deptList"
|
|
:isTopLabelExist="false"
|
|
:isBottomLabelExist="false"
|
|
>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<div class="h-[300px]">
|
|
<BarChart
|
|
id="dashboard_chart_week_comparison"
|
|
class="h-full"
|
|
:option="weekComparisonOption"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.chart-data:before {
|
|
@apply absolute right-0 left-2 top-0 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-0 bottom-0 h-10 w-10 bg-no-repeat z-10;
|
|
content: "";
|
|
background: url(@ASSET/img/chart-data-background02.svg) center center;
|
|
}
|
|
</style> |