152 lines
3.9 KiB
Vue
152 lines
3.9 KiB
Vue
<script setup>
|
|
import { ref, computed, watch, onUnmounted } from "vue";
|
|
import { useRouter } from "vue-router";
|
|
import { getSystemStatus } from "@/apis/headquarters";
|
|
import useBuildingStore from "@/stores/useBuildingStore";
|
|
import SysProgressModal from "./SysProgressModal.vue";
|
|
import { useI18n } from "vue-i18n";
|
|
|
|
const { t } = useI18n();
|
|
const router = useRouter();
|
|
const store = useBuildingStore();
|
|
const equipmentData = ref([]);
|
|
const modalData = ref({});
|
|
let intervalId = null;
|
|
|
|
const openModal = (item) => {
|
|
modalData.value = item;
|
|
system_status_modal.showModal();
|
|
};
|
|
|
|
const onCancel = () => {
|
|
modalData.value = {};
|
|
system_status_modal.close();
|
|
};
|
|
|
|
const getAlarmsInfos = async () => {
|
|
try {
|
|
const res = await getSystemStatus({
|
|
building_ids: store.buildings.map((building) => building.building_guid),
|
|
});
|
|
const apiData = res.data;
|
|
|
|
// 轉換 equipmentData 的資料格式
|
|
if (apiData && apiData.alarm) {
|
|
equipmentData.value = apiData.alarm.map((item) => ({
|
|
label: item.system_name,
|
|
online: item.online || 0,
|
|
offline: item.offline || 0,
|
|
alarm: item.alarm || 0,
|
|
}));
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching alarm info:", error);
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => store.buildings,
|
|
(newBuilding) => {
|
|
if (newBuilding) {
|
|
getAlarmsInfos();
|
|
|
|
if (intervalId) {
|
|
clearInterval(intervalId);
|
|
}
|
|
intervalId = setInterval(() => {
|
|
getAlarmsInfos();
|
|
}, 30000);
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
onUnmounted(() => {
|
|
clearInterval(intervalId);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<SysProgressModal :onCancel="onCancel" :modalData="modalData" />
|
|
<div class="w-full state-box-col relative">
|
|
<div class="state-box">
|
|
<div class="title">
|
|
<img class="state-title01" src="@ASSET/img/state-title01.svg" />
|
|
<span class="">{{$t("dashboard.system_status")}}</span>
|
|
<img class="state-title02" src="@ASSET/img/state-title02.svg" />
|
|
</div>
|
|
<table class="table table-sm text-center">
|
|
<thead>
|
|
<tr class="border-cyan-400 text-cyan-100">
|
|
<th></th>
|
|
<th>{{ $t("alert.online") }}</th>
|
|
<th>{{ $t("alert.offline") }}</th>
|
|
<th>{{ $t("alert.alarm") }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr
|
|
v-for="(item, index) in equipmentData"
|
|
:key="index"
|
|
class="border-cyan-400 cursor-pointer hover:text-info"
|
|
@click.stop.prevent="openModal(item)"
|
|
>
|
|
<th class="px-0 text-start">{{ item.label }}</th>
|
|
<td>
|
|
{{ item.online.length }}
|
|
</td>
|
|
<td>
|
|
{{ item.offline.length }}
|
|
</td>
|
|
<td>
|
|
{{ item.alarm.length }}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.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);
|
|
}
|
|
|
|
.state-box-col {
|
|
@apply border border-light-info shadow-md shadow-blue-300 rounded-sm py-2 px-6 text-white relative;
|
|
}
|
|
|
|
.state-box:after {
|
|
@apply absolute right-3 top-3 w-4 h-4 bg-no-repeat bg-center z-10;
|
|
content: "";
|
|
background-image: url(@ASSET/img/state-title01.svg);
|
|
}
|
|
|
|
.state-box:before {
|
|
@apply absolute right-0.5 bottom-5 w-4 h-32 bg-no-repeat bg-center z-10;
|
|
content: "";
|
|
background-image: url(@ASSET/img/state-ul-background02.svg);
|
|
}
|
|
|
|
.state-box .title {
|
|
@apply relative flex items-center mb-1;
|
|
}
|
|
|
|
.state-box .title .state-title01 {
|
|
@apply w-4 mr-1.5;
|
|
}
|
|
|
|
.state-box .title .state-title02 {
|
|
@apply w-5 ml-1.5;
|
|
}
|
|
</style>
|