141 lines
3.6 KiB
Vue
141 lines
3.6 KiB
Vue
<script setup>
|
|
import { ref, watch, computed, onUnmounted } from "vue";
|
|
import { getSystemEnergyCostRank } from "@/apis/headquarters";
|
|
import { useI18n } from "vue-i18n";
|
|
import useBuildingStore from "@/stores/useBuildingStore";
|
|
|
|
const store = useBuildingStore();
|
|
const { t } = useI18n();
|
|
|
|
const energyCostData = ref({});
|
|
const energyTypeList = ref([
|
|
{
|
|
title: t("dashboard.today_energy_consumption"),
|
|
key: "day",
|
|
},
|
|
{
|
|
title: t("dashboard.this_month_energy_consumption"),
|
|
key: "month",
|
|
},
|
|
]);
|
|
const currentEnergyType = ref({
|
|
name: "month",
|
|
});
|
|
let intervalId = null;
|
|
|
|
const currentEnergyData = computed(() => {
|
|
if (!energyCostData.value) {
|
|
return [];
|
|
}
|
|
return currentEnergyType.value.name === "month"
|
|
? energyCostData.value?.month || []
|
|
: energyCostData.value?.day || [];
|
|
});
|
|
|
|
const getEnergyRank = async () => {
|
|
try {
|
|
const res = await getSystemEnergyCostRank({
|
|
building_ids: store.buildings.map((building) => building.building_guid),
|
|
});
|
|
energyCostData.value = res.data;
|
|
} catch (error) {
|
|
console.error("Error fetching energy cost rank:", error);
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => store.buildings,
|
|
(newBuilding) => {
|
|
if (newBuilding) {
|
|
getEnergyRank();
|
|
|
|
if (intervalId) {
|
|
clearInterval(intervalId);
|
|
}
|
|
intervalId = setInterval(() => {
|
|
getEnergyRank();
|
|
}, 60 * 60 * 1000);
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
onUnmounted(() => {
|
|
clearInterval(intervalId);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="state-box-col relative">
|
|
<!-- 標題和切換按鈕 -->
|
|
<div class="flex justify-between items-center mb-2">
|
|
<h2 class="font-light relative">
|
|
{{ $t("dashboard.energy_ranking") }}
|
|
</h2>
|
|
<Select
|
|
:value="currentEnergyType"
|
|
class="!w-24"
|
|
selectClass="border-info focus-within:border-info btn-xs text-xs"
|
|
name="name"
|
|
Attribute="title"
|
|
:options="energyTypeList"
|
|
:isTopLabelExist="false"
|
|
:isBottomLabelExist="false"
|
|
>
|
|
</Select>
|
|
</div>
|
|
|
|
<!-- 能耗排名列表 -->
|
|
<div class="overflow-y-auto" style="height: 200px;">
|
|
<table class="table table-sm text-center">
|
|
<tbody>
|
|
<tr
|
|
v-for="(item, index) in currentEnergyData"
|
|
:key="index"
|
|
:class="[
|
|
{ 'text-red-300': index + 1 === 1 },
|
|
{ 'text-orange-300': index + 1 === 2 },
|
|
{ 'text-yellow-300': index + 1 === 3 },
|
|
{ 'text-teal-300': index + 1 > 3 },
|
|
]"
|
|
>
|
|
<td class="px-0 align-top">
|
|
<p class="flex items-center">
|
|
<font-awesome-icon :icon="['fas', 'crown']" class="me-1" />
|
|
{{ index + 1 }}
|
|
</p>
|
|
</td>
|
|
<td class="align-top whitespace-nowrap px-0">
|
|
{{ item.site_name }}
|
|
</td>
|
|
<td class="align-top">{{ item.name }}</td>
|
|
<td class="align-top ps-0">{{ item.value }}</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.state-box-col {
|
|
@apply border-2 border-light-info rounded-sm p-2 text-white relative;
|
|
}
|
|
|
|
.state-box-col:before {
|
|
@apply absolute left-0 right-0 -top-0.5 m-auto h-2 w-36 bg-no-repeat bg-center z-10;
|
|
content: "";
|
|
background-image: url(@ASSET/img/state-box-top.png);
|
|
}
|
|
|
|
.state-box-col:after {
|
|
@apply absolute left-0 right-0 -bottom-0.5 m-auto h-2 w-36 bg-no-repeat bg-center z-10;
|
|
content: "";
|
|
background-image: url(@ASSET/img/state-box-bottom.png);
|
|
}
|
|
|
|
tr td {
|
|
@apply text-[13px] text-start;
|
|
}
|
|
</style>
|