首頁UI | debug: 頁面重新整理時會回首頁 | sidebar 語言包 | 能源管理 : 增長率 多去年資料

This commit is contained in:
koko 2025-08-05 13:49:52 +08:00
parent 73a76aca2e
commit e05e83bb03
17 changed files with 219 additions and 179 deletions

BIN
public/CviLux_globalmap.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View File

@ -4,3 +4,4 @@ export const DELETE_BUILDING_API = `/AssetManage/DeleteBuilding`;
export const GET_AUTHPAGE_API = `/api/GetUsrFroList`;
export const GET_SUBAUTHPAGE_API = `/api/Device/GetMainSub`;
export const GET_ALL_DEVICE_API = `/api/Device/GetAllDevice`;
export const GET_FUNCTION_LIST_API = `/api/function/get-function-list`;

View File

@ -5,6 +5,7 @@ import {
GET_AUTHPAGE_API,
GET_SUBAUTHPAGE_API,
GET_ALL_DEVICE_API,
GET_FUNCTION_LIST_API,
} from "./api";
import instance from "@/util/request";
import apihandler from "@/util/apihandler";
@ -39,9 +40,9 @@ export const deleteBuildings = async (building_guid) => {
});
};
export const getAuth = async (build) => {
const res = await instance.post(GET_AUTHPAGE_API, {
build,
export const getAuth = async (building_id) => {
const res = await instance.get(GET_FUNCTION_LIST_API, {
params: { building_id },
});
return apihandler(res.code, res.data, {
msg: res.msg,

View File

@ -1,6 +1,6 @@
export const GET_REALTIME_DIST_API = `/api/Energe/GetRealTimeDistribution`;
export const GET_ELECUSE_DAY_API = `/api/Energe/GetElecUseDay`;
export const GET_TAI_POWER_API = `/api/Energe/GetTaipower`;
export const GET_TAI_POWER_API = `/api/energy-manager/power-usage`;
export const GET_SIDEBAR_API = `/api/GetSideBar`;
export const GET_SEARCH_API = `/api/Energe/GetFilter`;

View File

@ -7,24 +7,17 @@ const store = useBuildingStore();
const router = useRouter();
const selectBuilding = (bui) => {
store.selectedBuilding = bui; // selectedBuildingwatch
if (bui.is_headquarter == true) {
router.replace({ path: "/headquarters" });
} else {
router.replace({ path: "/dashboard" });
}
};
onMounted(() => {
store.initialize(); //
});
watch(
() => store.selectedBuilding,
(newValue) => {
console.log('Selected building changed:', newValue);
if (newValue.is_headquarter == true) {
router.replace({ path: "/headquarters" });
} else {
router.replace({ path: "/dashboard" });
}
}
);
</script>
<template>

View File

@ -9,7 +9,7 @@ import { useI18n } from "vue-i18n";
import { useRoute } from "vue-router";
import { twMerge } from "tailwind-merge";
const { locale } = useI18n();
const { locale, t } = useI18n();
const store = useUserInfoStore();
const buildingStore = useBuildingStore();
const route = useRoute();
@ -17,8 +17,8 @@ const openKeys = ref([]); // 追蹤當前打開的子菜單
const menu_array = ref([]);
const currentAuthCode = ref("");
const iniFroList = async (build) => {
const res = await getAuth(build);
const iniFroList = async (building_id) => {
const res = await getAuth(building_id);
store.updateAuthPage(
res.data.map((d) =>
@ -167,7 +167,7 @@ watch(
<a-sub-menu
v-for="main in menu_array"
:key="main.main_system_tag"
:title="main.full_name"
:title="main.resource ? t(`navbar.${main.resource}`) : main.full_name"
v-if="menu_array.length > 0 && open"
>
<a-menu-item
@ -196,7 +196,7 @@ watch(
},
}"
>
{{ sub.full_name }}
{{ sub.resource ? $t(`navbar.${sub.resource}`): sub.full_name }}
</router-link>
</a-menu-item>
</a-sub-menu>

View File

@ -23,7 +23,27 @@
"graphManagement": "图资管理",
"AssetManagement": "资产管理",
"accountManagement": "帐号管理",
"Setting": "系统设定"
"Setting": "系统设定",
"energy_analysis": "能源分析",
"consumption_report": "用电报表",
"chart_analysis": "图表分析",
"historical_curve": "历史曲线",
"quick_metering": "快速抄表",
"electricity_classification": "用电分类",
"daily_report": "日报表",
"weekly_report": "周报表",
"monthly_report": "月报表",
"annual_report": "年报表",
"setting":"系统设置",
"device":"设置设置",
"department": "部门",
"settings_2d_3d": "2D/3D 显示设置",
"maintenance_vendor": "维修厂商",
"building": "厂区",
"floor": "楼层",
"demand": "电表",
"time_based_pricing": "时段电价",
"mqtt_result": "MQTT 结果"
},
"upload": {
"title": "选择一个文件或拖放到这里",
@ -101,11 +121,11 @@
"reset_value": "复归值",
"edit_automatic_demand": "编辑自动需量",
"elec_bills": "今年电费累计(元)",
"interval_elec_charges": "区间电费(元)",
"interval_elec_charges": "本月电费(元)",
"year_carbon_emission": "今年碳排当量累计(公斤)",
"interval_carbon_emission": "区间碳排当量",
"interval_carbon_emission": "本月碳排当量",
"year_elec_consumption": "今年用电度数(kWh)",
"interval_elec_consumption": "区间用电度数(kWh)",
"interval_elec_consumption": "本月用电度数(kWh)",
"monthly_elec_consumption": "每月用电分析",
"monthly_carbon_emission_and_reduction": "每月碳排当量 (kgCO2e)",
"monthly_bill_power": "每月计费度数 (kWh)",
@ -167,7 +187,9 @@
"off_peak_contract": "离峰契约",
"variable_electricity_charge": "流动电费",
"saturday": "周六",
"sunday_and_off_peak_days": "周日及离峰日"
"sunday_and_off_peak_days": "周日及离峰日",
"past_elec_data": "去年±数值(百分比)",
"past_month_elec_data": "上月±数值(百分比)"
},
"alarm": {
"title": "显示警告",

View File

@ -15,21 +15,35 @@
},
"navbar": {
"home": "首頁",
"sysMonBtnList": "系統監控",
"sysMonBtnList": "系統監控",
"historyData": "歷史資料",
"energyManagement": "能源管理",
"energyManagement": "能源管理",
"alert": "告警",
"operation": "運維管理",
"graphManagement": "圖資管理",
"AssetManagement": "資產管理",
"accountManagement": "帳號管理",
"Setting": "系統設定",
"energy":{
"energy_chart": "能耗圖表",
"energy_report": "能耗報表",
"chart":"圖表分析",
"history":"歷史資料"
}
"energy_analysis": "能耗分析",
"consumption_report": "用電報表",
"chart_analysis": "圖表分析",
"historical_curve": "歷史曲線",
"quick_metering": "快速抄表",
"electricity_classification": "用電分類",
"daily_report": "日報表",
"weekly_report": "周報表",
"monthly_report": "月報表",
"annual_report": "年報表",
"setting":"系統設定",
"device":"設備設定",
"department": "部門",
"settings_2d_3d": "2D/3D 顯示設定",
"maintenance_vendor": "維運廠商",
"building": "廠區",
"floor": "樓層",
"demand": "電表",
"time_based_pricing": "時段電價",
"mqtt_result": "MQTT 結果"
},
"upload": {
"title": "選擇一個文件或拖放到這裡",
@ -107,11 +121,11 @@
"reset_value": "復歸值",
"edit_automatic_demand": "編輯自動需量",
"elec_bills": "今年電費累計(元)",
"interval_elec_charges": "區間電費(元)",
"interval_elec_charges": "本月電費(元)",
"year_carbon_emission": "今年碳排當量累計(公斤)",
"interval_carbon_emission": "區間碳排當量",
"interval_carbon_emission": "本月碳排當量",
"year_elec_consumption": "今年用電度數(kWh)",
"interval_elec_consumption": "區間用電度數(kWh)",
"interval_elec_consumption": "本月用電度數(kWh)",
"monthly_elec_consumption": "每月用電分析",
"monthly_carbon_emission_and_reduction": "每月碳排當量 (kgCO2e)",
"monthly_bill_power": "每月計費度數 (kWh)",
@ -173,7 +187,9 @@
"off_peak_contract": "離峰契約",
"variable_electricity_charge": "流動電費",
"saturday": "週六",
"sunday_and_off_peak_days": "週日及離峰日"
"sunday_and_off_peak_days": "週日及離峰日",
"past_elec_data": "去年±數值(百分比)",
"past_month_elec_data": "上月±數值(百分比)"
},
"alarm": {
"title": "顯示警告",
@ -419,12 +435,12 @@
"delete_failed": "刪除失敗",
"mqtt_refresh": "重新設定成功",
"schema_name_required": "架構名稱欄位必填",
"incorrect_format":"格式不正確",
"send_successfully":"送出成功",
"edit_successfully":"修改成功"
"incorrect_format": "格式不正確",
"send_successfully": "送出成功",
"edit_successfully": "修改成功"
},
"setting": {
"electricity_meter":"電表",
"electricity_meter": "電表",
"MQTT_parse": "MQTT 解析",
"schema": "架構",
"point": "點位",

View File

@ -23,7 +23,27 @@
"graphManagement": "Graph",
"AssetManagement": "Devices",
"accountManagement": "Account",
"Setting": "Setting"
"Setting": "Setting",
"energy_analysis": "Energy Analysis",
"consumption_report": "Consumption Report",
"chart_analysis": "Chart Analysis",
"historical_curve": "Historical Curve",
"quick_metering": "Quick Metering",
"electricity_classification": "Electricity Classification",
"daily_report": "Daily Report",
"weekly_report": "Weekly Report",
"monthly_report": "Monthly Report",
"annual_report": "Annual Report",
"setting":"Settings",
"device":"Device",
"department": "Department",
"settings_2d_3d": "2D/3D Display Settings",
"maintenance_vendor": "Vendor",
"building": "Building",
"floor": "Floor",
"demand": "Demand",
"time_based_pricing": "Time-based Pricing",
"mqtt_result": "MQTT Result"
},
"upload": {
"title": "Select a file or drag and drop here",
@ -101,11 +121,11 @@
"reset_value": "Reset Value",
"edit_automatic_demand": "Edit automatic demand",
"elec_bills": "Total electricity bills this year (yuan)",
"interval_elec_charges": "Interval electricity charges (yuan)",
"interval_elec_charges": "Electricity charges for this month (yuan)",
"year_carbon_emission": "Cumulative carbon emission equivalent this year (kg)",
"interval_carbon_emission": "Interval carbon emission equivalent",
"interval_carbon_emission": "This month's carbon emission equivalent",
"year_elec_consumption": "This year's electricity consumption (kWh)",
"interval_elec_consumption": "Interval electricity consumption (kWh)",
"interval_elec_consumption": "This month's electricity consumption (kWh)",
"monthly_elec_consumption": "Monthly electricity consumption analysis",
"monthly_carbon_emission_and_reduction": "Monthly carbon emission equivalent (kgCO2e)",
"monthly_bill_power": "Monthly billing power (kWh)",
@ -167,7 +187,9 @@
"off_peak_contract": "Off-Peak Demand Charge",
"variable_electricity_charge": "Variable Electricity Charge",
"saturday": "Saturday",
"sunday_and_off_peak_days": "Sunday and Off-Peak Days"
"sunday_and_off_peak_days": "Sunday and Off-Peak Days",
"past_elec_data": "Last year ± value (percentage)",
"past_month_elec_data": "Last month ± value (percentage)"
},
"alarm": {
"title": "Warning",

View File

@ -28,6 +28,7 @@ const {
} = useActiveBtn("multiple");
const taipower_data = ref([]);
const yearly_taipower_data = ref([]);
const carbonValue = ref(null);
const search_data = computed(() => {
return {
@ -41,9 +42,10 @@ const search_data = computed(() => {
const getData = async (value) => {
const res = await getTaipower(value);
if (res.isSuccess) {
taipower_data.value = res.data
? res.data.sort((a, b) => a.month.localeCompare(b.month))
taipower_data.value = res.data?.monthlyUsage
? res.data?.monthlyUsage.sort((a, b) => a.month.localeCompare(b.month))
: [];
yearly_taipower_data.value = res.data?.yearlyUsage;
}
};
@ -96,7 +98,12 @@ watch(
}
);
provide("energy_data", { taipower_data, search_data, carbonValue });
provide("energy_data", {
taipower_data,
yearly_taipower_data,
search_data,
carbonValue,
});
</script>
<template>

View File

@ -4,7 +4,7 @@ import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n";
const { t, locale } = useI18n();
const { taipower_data } = inject("energy_data");
const { taipower_data, yearly_taipower_data } = inject("energy_data");
const daysInMonth = (month) => {
const [year, monthNumber] = month.split("-");
@ -19,7 +19,10 @@ const calculateData = () => {
item.month.startsWith(currentYear)
);
const totalElecBills = filteredData.reduce((sum, item) => sum + item.costTotal, 0);
const totalElecBills = filteredData.reduce(
(sum, item) => sum + item.costTotal,
0
);
const latestMonthData = filteredData[filteredData.length - 1];
const latestMonth = latestMonthData ? latestMonthData.month : "";
const monthDays = latestMonth ? daysInMonth(latestMonth) : 0;
@ -37,29 +40,53 @@ const calculateData = () => {
);
return [
{ title: t("energy.elec_bills"), data: totalElecBills.toLocaleString() },
{
title: t("energy.elec_bills"),
data: totalElecBills.toLocaleString(),
past: yearly_taipower_data.value.costTotalGrowthPercent
? yearly_taipower_data.value.costTotalGrowthPercent.toLocaleString()
: 0,
},
{
title: t("energy.interval_elec_charges"),
time: monthTxt,
data: latestMonthData ? latestMonthData.costTotal.toLocaleString() : 0,
past:
latestMonthData && latestMonthData.costTotalGrowthPercent
? latestMonthData.costTotalGrowthPercent.toLocaleString()
: 0,
},
{
title: t("energy.year_carbon_emission"),
data: totalCarbonEmission.toLocaleString(),
past: yearly_taipower_data.value.carbonGrowthPercent
? yearly_taipower_data.value.carbonGrowthPercent.toLocaleString()
: 0,
},
{
title: t("energy.interval_carbon_emission"),
time: monthTxt,
data: latestMonthData ? latestMonthData.carbon.toLocaleString() : 0,
past:
latestMonthData && latestMonthData.carbonGrowthPercent
? latestMonthData.carbonGrowthPercent.toLocaleString()
: 0,
},
{
title: t("energy.year_elec_consumption"),
data: totalElecConsumption.toLocaleString(),
past: yearly_taipower_data.value.kWhGrowthPercent
? yearly_taipower_data.value.kWhGrowthPercent.toLocaleString()
: 0,
},
{
title: t("energy.interval_elec_consumption"),
time: monthTxt,
data: latestMonthData ? latestMonthData.kWh.toLocaleString() : 0,
past:
latestMonthData && latestMonthData.kWhGrowthPercent
? latestMonthData.kWhGrowthPercent.toLocaleString()
: 0,
},
];
};
@ -95,7 +122,9 @@ watch(
>
<div class="title">{{ item.title }}</div>
<div v-if="item.time" class="time">{{ item.time }}</div>
<div class="data">{{ item.data }}</div>
<div class="data">
<span>{{ item.data }}</span> / <span>{{ item.past }}</span>
</div>
</div>
</div>
</template>

View File

@ -4,78 +4,20 @@ import SysProgress from "./components/SysProgress.vue";
import ElecRank from "./components/ElecRank.vue";
import ElecTrends from "./components/ElecTrends.vue";
import ElecCompare from "./components/ElecCompare.vue";
import { getEnergyCost } from "@/apis/dashboard";
import useBuildingStore from "@/stores/useBuildingStore";
const store = useBuildingStore();
let intervalId = null;
const energyCostData = ref({});
const formState = ref({
building_guid: null,
floor_guid: "all",
department_id: "all",
});
const getEnergyCostData = async (params) => {
const res = await getEnergyCost(params);
energyCostData.value = res.data;
};
watch(
() => store.selectedBuilding,
(newBuilding) => {
if (newBuilding) {
formState.value.building_guid = newBuilding.building_guid;
}
},
{ immediate: true, deep: true }
);
watch(
() => formState.value,
(newVal) => {
if (newVal) {
const params = { ...newVal };
if (params.floor_guid === "all") {
delete params.floor_guid;
}
if (params.department_id === "all") {
delete params.department_id;
}
if (params.building_guid) {
getEnergyCostData(params);
}
if (intervalId) {
clearInterval(intervalId);
}
//
intervalId = setInterval(() => {
getEnergyCostData(params);
}, 60 * 60 * 1000);
}
},
{ immediate: true, deep: true }
);
onUnmounted(() => {
clearInterval(intervalId);
});
</script>
<template>
<div class="flex gap-4">
<div class="w-full xl:w-1/4 mt-2">
<div class="grid grid-cols-1 xl:grid-cols-4 gap-4 my-2">
<div class="col-span-1 grid grid-cols-1 md:grid-cols-2 md:grid-rows-1 xl:grid-cols-1 xl:grid-rows-2 gap-4">
<div class="area-img-box">
<img
alt="build"
src="/build_img.jpg"
class="w-full h-48 object-cover border-cyan-400 shadow-cyan-500/40"
class="w-full object-cover border-cyan-400 shadow-cyan-500/40"
/>
<p
class="p-4 text-gray-100 text-base font-light bg-gray-800/60 rounded-b-xl backdrop-blur-md border-t border-cyan-400/30 shadow-inner"
class="p-4 h-full text-gray-100 text-base font-light bg-gray-800/60 backdrop-blur-md border-t border-cyan-400/30 shadow-inner"
>
深耕電子精密連接器光通信元件軟性排線線纜組件PCBA電子機板電子成品專業製造廠並代理電子零組件做為整合行銷公司創立於1990年產品行銷全球以穩定快速以及高品質知名;
未來瀚荃會持續精進提供更快更好以及高附加價值的產品與服務來滿足您的需求
@ -84,14 +26,14 @@ onUnmounted(() => {
<!--在線狀態-->
<SysProgress />
</div>
<div class="w-full xl:w-2/4 max-h-[calc(100vh-90px)] mt-2 border border-cyan-400 shadow-md shadow-cyan-500/40">
<div class="col-span-2 h-full border border-cyan-400 shadow-md shadow-cyan-500/40">
<img
src="/CviLux_globalmap.jpg"
src="/CviLux_globalmap.png"
alt=""
class="w-full h-full invert object-cover "
class="w-full h-full object-cover "
/>
</div>
<div class="w-full xl:w-1/4 mt-2">
<div class="col-span-1 grid grid-cols-1 xl:grid-rows-3 gap-4">
<ElecRank />
<ElecTrends
/>
@ -102,6 +44,6 @@ onUnmounted(() => {
<style lang="scss" scoped>
.area-img-box {
@apply border border-light-info bg-gray-900/80 backdrop-blur-lg relative overflow-hidden shadow-md shadow-blue-300 mb-4;
@apply border border-light-info bg-gray-900/80 backdrop-blur-lg relative overflow-hidden shadow-md shadow-blue-300;
}
</style>

View File

@ -226,7 +226,7 @@ onUnmounted(() => {
<template>
<div class="flex flex-wrap">
<div class="w-full chart-data relative px-3 mb-3">
<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.relative_energy_consumption") }}

View File

@ -66,59 +66,59 @@ onUnmounted(() => {
</script>
<template>
<div class="state-box-col relative h-full max-h-[190px] mb-3">
<div class="state-box h-full">
<!-- 標題和切換按鈕 -->
<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="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="max-h-[140px] overflow-y-auto">
<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 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 {
.state-box-col {
@apply border-2 border-light-info rounded-sm p-2 text-white relative;
}

View File

@ -83,8 +83,8 @@ const generateCylinderChartOption = (data) => {
grid: {
left: "0%",
right: "0%",
bottom: "3%",
top: "17%",
bottom: "0%",
top: "16%",
containLabel: true,
},
tooltip: {
@ -100,7 +100,7 @@ const generateCylinderChartOption = (data) => {
const processEnergyData = async () => {
try {
const res = await getSystemEnergyCostTrend({
building_ids: [currentType.value.name],
building_id: currentType.value.name,
});
energyCostData.value = res.data.trend || [];
if (!energyCostData.value || energyCostData.value.length === 0) {
@ -166,7 +166,7 @@ onUnmounted(() => {
</script>
<template>
<div class="w-full chart-data relative px-3 mb-3">
<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") }}
@ -201,7 +201,7 @@ onUnmounted(() => {
}
.chart-data::after {
@apply absolute -right-1 -bottom-1 h-10 w-10 bg-no-repeat z-10;
@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;
}

View File

@ -124,8 +124,8 @@ onUnmounted(() => {
background-image: url(@ASSET/img/state-box-bottom.png);
}
.state-box {
@apply h-[21rem] border border-light-info shadow-md shadow-blue-300 rounded-sm py-2 px-6 mb-2 text-white relative;
.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 {

View File

@ -37,8 +37,15 @@ const doLogin = async () => {
const res = await Login(value);
if (res.isSuccess) {
store.user = res.data;
localStorage.setItem("CviBuildingList", JSON.stringify(res.data.building_infos));
router.replace({ path: "/dashboard" });
localStorage.setItem(
"CviBuildingList",
JSON.stringify(res.data.building_infos)
);
if (res.data.building_infos.map((b) => b.is_headquarter).includes(true)) {
router.replace({ path: "/headquarters" });
} else {
router.replace({ path: "/dashboard" });
}
} else {
openToast("error", res.msg);
}