總部首頁 api 串接 | navbar語言包
This commit is contained in:
parent
1812ce2495
commit
db5f15dfde
@ -39,9 +39,9 @@ export const deleteBuildings = async (building_guid) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getAuth = async (lang) => {
|
export const getAuth = async (build) => {
|
||||||
const res = await instance.post(GET_AUTHPAGE_API, {
|
const res = await instance.post(GET_AUTHPAGE_API, {
|
||||||
lang,
|
build,
|
||||||
});
|
});
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
@ -50,7 +50,7 @@ export const getAuth = async (lang) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getAllSysSidebar = async (building_guid) => {
|
export const getAllSysSidebar = async (building_guid) => {
|
||||||
const res = await instance.post(GET_SUBAUTHPAGE_API, {building_guid});
|
const res = await instance.post(GET_SUBAUTHPAGE_API, { building_guid });
|
||||||
return apihandler(res.code, res.data, {
|
return apihandler(res.code, res.data, {
|
||||||
msg: res.msg,
|
msg: res.msg,
|
||||||
code: res.code,
|
code: res.code,
|
||||||
|
6
src/apis/headquarters/api.js
Normal file
6
src/apis/headquarters/api.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export const GET_SITES_SYSTEM_STATUS_API = `/api/monitoring/sites-system-status`;
|
||||||
|
export const GET_SITES_SYSTEM_ENERGY_COST_RANK_API = `/api/energy-manager/all-site/energy-cost-rank`;
|
||||||
|
export const GET_SITES_SYSTEM_ENERGY_COST_TREND_API = `/api/energy-manager/all-site/energy-cost-trend`;
|
||||||
|
export const GET_SITES_SYSTEM_ENERGY_COST_GROWTH_API = `/api/energy-manager/all-site/energy-cost-growth-rate`;
|
||||||
|
|
||||||
|
|
44
src/apis/headquarters/index.js
Normal file
44
src/apis/headquarters/index.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
GET_SITES_SYSTEM_STATUS_API,
|
||||||
|
GET_SITES_SYSTEM_ENERGY_COST_RANK_API,
|
||||||
|
GET_SITES_SYSTEM_ENERGY_COST_TREND_API,
|
||||||
|
GET_SITES_SYSTEM_ENERGY_COST_GROWTH_API,
|
||||||
|
} from "./api";
|
||||||
|
import instance from "@/util/request";
|
||||||
|
import apihandler from "@/util/apihandler";
|
||||||
|
|
||||||
|
export const getSystemStatus = async (building_ids) => {
|
||||||
|
const res = await instance.post(GET_SITES_SYSTEM_STATUS_API, building_ids);
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSystemEnergyCostRank = async (building_ids) => {
|
||||||
|
const res = await instance.post(GET_SITES_SYSTEM_ENERGY_COST_RANK_API, building_ids);
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getSystemEnergyCostTrend = async (building_ids) => {
|
||||||
|
const res = await instance.post(GET_SITES_SYSTEM_ENERGY_COST_TREND_API, building_ids);
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getSystemEnergyCostGrowth = async (building_ids) => {
|
||||||
|
const res = await instance.get(GET_SITES_SYSTEM_ENERGY_COST_GROWTH_API, building_ids);
|
||||||
|
|
||||||
|
return apihandler(res.code, res.data, {
|
||||||
|
msg: res.msg,
|
||||||
|
code: res.code,
|
||||||
|
});
|
||||||
|
}
|
@ -1,9 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted } from "vue";
|
import { onMounted,watch } from "vue";
|
||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
const store = useBuildingStore();
|
const store = useBuildingStore();
|
||||||
|
const router = useRouter();
|
||||||
const selectBuilding = (bui) => {
|
const selectBuilding = (bui) => {
|
||||||
store.selectedBuilding = bui; // 改變 selectedBuilding,watch 會自動更新資料
|
store.selectedBuilding = bui; // 改變 selectedBuilding,watch 會自動更新資料
|
||||||
};
|
};
|
||||||
@ -11,6 +12,19 @@ const selectBuilding = (bui) => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
store.initialize(); // 初始化資料
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -17,8 +17,8 @@ const openKeys = ref([]); // 追蹤當前打開的子菜單
|
|||||||
const menu_array = ref([]);
|
const menu_array = ref([]);
|
||||||
const currentAuthCode = ref("");
|
const currentAuthCode = ref("");
|
||||||
|
|
||||||
const iniFroList = async () => {
|
const iniFroList = async (build) => {
|
||||||
const res = await getAuth(locale.value);
|
const res = await getAuth(build);
|
||||||
|
|
||||||
store.updateAuthPage(
|
store.updateAuthPage(
|
||||||
res.data.map((d) =>
|
res.data.map((d) =>
|
||||||
@ -72,23 +72,21 @@ watch(
|
|||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal !== null) {
|
if (newVal !== null) {
|
||||||
getSubMonitorPage(newVal.building_guid);
|
getSubMonitorPage(newVal.building_guid);
|
||||||
|
iniFroList(newVal.building_guid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(locale, () => {
|
|
||||||
iniFroList();
|
|
||||||
});
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
iniFroList();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<ul class="px-1 menu-box my-2">
|
<ul class="px-1 menu-box my-2">
|
||||||
<li class="flex flex-col items-center justify-center">
|
<li class="flex flex-col items-center justify-center">
|
||||||
<router-link
|
<router-link
|
||||||
:to="{ name: 'dashboard' }"
|
:to="{
|
||||||
|
name:
|
||||||
|
buildingStore.selectedBuilding?.is_headquarter === true
|
||||||
|
? 'headquarters'
|
||||||
|
: 'dashboard',
|
||||||
|
}"
|
||||||
class="flex lg:flex-col justify-center items-center btn-group text-white"
|
class="flex lg:flex-col justify-center items-center btn-group text-white"
|
||||||
>
|
>
|
||||||
<font-awesome-icon
|
<font-awesome-icon
|
||||||
@ -96,7 +94,7 @@ onMounted(() => {
|
|||||||
size="2x"
|
size="2x"
|
||||||
class="w-10 m-auto"
|
class="w-10 m-auto"
|
||||||
/>
|
/>
|
||||||
<span>{{ $t("home") }}</span>
|
<span>{{ $t("navbar.home") }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
@ -132,11 +130,11 @@ onMounted(() => {
|
|||||||
size="2x"
|
size="2x"
|
||||||
class="w-10 m-auto"
|
class="w-10 m-auto"
|
||||||
/>
|
/>
|
||||||
<span>{{ page.subName }}</span>
|
<span>{{ $t(`navbar.${page.showView}`) }}</span>
|
||||||
</a>
|
</a>
|
||||||
<router-link
|
<router-link
|
||||||
v-else
|
v-else
|
||||||
:to="page.navigate"
|
:to="`/` + page.showView"
|
||||||
type="link"
|
type="link"
|
||||||
class="flex lg:flex-col justify-center items-center btn-group text-white"
|
class="flex lg:flex-col justify-center items-center btn-group text-white"
|
||||||
>
|
>
|
||||||
@ -145,7 +143,7 @@ onMounted(() => {
|
|||||||
size="2x"
|
size="2x"
|
||||||
class="w-10 m-auto"
|
class="w-10 m-auto"
|
||||||
/>
|
/>
|
||||||
<span>{{ page.subName }}</span>
|
<span>{{ $t(`navbar.${page.showView}`) }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -192,7 +190,7 @@ onMounted(() => {
|
|||||||
params: {
|
params: {
|
||||||
main_system_id: main.main_system_tag,
|
main_system_id: main.main_system_tag,
|
||||||
sub_system_id: sub.sub_system_tag,
|
sub_system_id: sub.sub_system_tag,
|
||||||
...(currentAuthCode === 'PF2' || currentAuthCode === 'PF11'
|
...(currentAuthCode === 'PF2' || currentAuthCode === 'PF11'
|
||||||
? { type: sub.type }
|
? { type: sub.type }
|
||||||
: { floor_id: 'main' }),
|
: { floor_id: 'main' }),
|
||||||
},
|
},
|
||||||
|
@ -13,6 +13,18 @@
|
|||||||
"name": "名称",
|
"name": "名称",
|
||||||
"time": "时间"
|
"time": "时间"
|
||||||
},
|
},
|
||||||
|
"navbar": {
|
||||||
|
"home": "首页",
|
||||||
|
"sysMonBtnList": "系统监控",
|
||||||
|
"historyData": "历史资料",
|
||||||
|
"energyManagement": "能源管理",
|
||||||
|
"alert": "告警",
|
||||||
|
"operation": "运维管理",
|
||||||
|
"graphManagement": "图资管理",
|
||||||
|
"AssetManagement": "资产管理",
|
||||||
|
"accountManagement": "帐号管理",
|
||||||
|
"Setting": "系统设定"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"title": "选择一个文件或拖放到这里",
|
"title": "选择一个文件或拖放到这里",
|
||||||
"description": "档案不超过 10MB",
|
"description": "档案不超过 10MB",
|
||||||
|
@ -10,9 +10,27 @@
|
|||||||
"in_otal": "筆資料",
|
"in_otal": "筆資料",
|
||||||
"skip_to": "跳至",
|
"skip_to": "跳至",
|
||||||
"serial_number": "序號",
|
"serial_number": "序號",
|
||||||
"name": "姓名",
|
"name": "名稱",
|
||||||
"time": "時間"
|
"time": "時間"
|
||||||
},
|
},
|
||||||
|
"navbar": {
|
||||||
|
"home": "首頁",
|
||||||
|
"sysMonBtnList": "系統監控",
|
||||||
|
"historyData": "歷史資料",
|
||||||
|
"energyManagement": "能源管理",
|
||||||
|
"alert": "告警",
|
||||||
|
"operation": "運維管理",
|
||||||
|
"graphManagement": "圖資管理",
|
||||||
|
"AssetManagement": "資產管理",
|
||||||
|
"accountManagement": "帳號管理",
|
||||||
|
"Setting": "系統設定",
|
||||||
|
"energy":{
|
||||||
|
"energy_chart": "能耗圖表",
|
||||||
|
"energy_report": "能耗報表",
|
||||||
|
"chart":"圖表分析",
|
||||||
|
"history":"歷史資料"
|
||||||
|
}
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"title": "選擇一個文件或拖放到這裡",
|
"title": "選擇一個文件或拖放到這裡",
|
||||||
"description": "檔案不超過 10MB",
|
"description": "檔案不超過 10MB",
|
||||||
|
@ -13,6 +13,18 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"time": "Time"
|
"time": "Time"
|
||||||
},
|
},
|
||||||
|
"navbar": {
|
||||||
|
"home": "Home",
|
||||||
|
"sysMonBtnList": "Monitoring",
|
||||||
|
"historyData": "History Data",
|
||||||
|
"energyManagement": "Energy",
|
||||||
|
"alert": "Alert",
|
||||||
|
"operation": "Maintenance",
|
||||||
|
"graphManagement": "Graph",
|
||||||
|
"AssetManagement": "Devices",
|
||||||
|
"accountManagement": "Account",
|
||||||
|
"Setting": "Setting"
|
||||||
|
},
|
||||||
"upload": {
|
"upload": {
|
||||||
"title": "Select a file or drag and drop here",
|
"title": "Select a file or drag and drop here",
|
||||||
"description": "File size cannot exceed 10MB",
|
"description": "File size cannot exceed 10MB",
|
||||||
|
@ -2,69 +2,49 @@ export const AUTHPAGES = [
|
|||||||
{
|
{
|
||||||
authCode: "PF0",
|
authCode: "PF0",
|
||||||
icon: "home",
|
icon: "home",
|
||||||
navigate: "/dashboard",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF1",
|
authCode: "PF1",
|
||||||
icon: "tv",
|
icon: "tv",
|
||||||
navigate: "/system",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF2",
|
authCode: "PF2",
|
||||||
icon: "chart-pie",
|
icon: "chart-pie",
|
||||||
pageName: "energyManagement",
|
|
||||||
navigate: "/energyManagement",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF3",
|
authCode: "PF3",
|
||||||
icon: "chart-area",
|
icon: "chart-area",
|
||||||
navigate: "/historyData",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF4",
|
authCode: "PF4",
|
||||||
icon: "chart-line",
|
icon: "chart-line",
|
||||||
navigate: "/historyData",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF5",
|
authCode: "PF5",
|
||||||
icon: "bell",
|
icon: "bell",
|
||||||
pageName: "alert",
|
|
||||||
navigate: "/alert",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF6",
|
authCode: "PF6",
|
||||||
icon: "server",
|
icon: "server",
|
||||||
pageName: "operation",
|
|
||||||
navigate: "/operation",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF7",
|
authCode: "PF7",
|
||||||
icon: "image",
|
icon: "image",
|
||||||
pageName: "graphManagement",
|
|
||||||
navigate: "/graphManagement",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF8",
|
authCode: "PF8",
|
||||||
icon: "user",
|
icon: "user",
|
||||||
pageName: "accountManagement",
|
|
||||||
navigate: "/accountManagement",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF9",
|
authCode: "PF9",
|
||||||
icon: "database",
|
icon: "database",
|
||||||
pageName: "AssetManagement",
|
|
||||||
navigate: "/assetManagement",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF10",
|
authCode: "PF10",
|
||||||
icon: "leaf",
|
icon: "leaf",
|
||||||
pageName: "ProductSetting",
|
|
||||||
navigate: "/productSetting",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
authCode: "PF11",
|
authCode: "PF11",
|
||||||
icon: "cog",
|
icon: "cog",
|
||||||
pageName: "Setting",
|
|
||||||
navigate: "/Setting",
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -107,7 +107,7 @@ const router = createRouter({
|
|||||||
router.beforeEach(async (to, from, next) => {
|
router.beforeEach(async (to, from, next) => {
|
||||||
console.log("route", to, location, document.cookie);
|
console.log("route", to, location, document.cookie);
|
||||||
// redirect to login page if not logged in and trying to access a restricted page
|
// redirect to login page if not logged in and trying to access a restricted page
|
||||||
const publicPages = ["/login", "/", "/headquarters"];
|
const publicPages = ["/login", "/"];
|
||||||
const authRequired = !publicPages.includes(to.path);
|
const authRequired = !publicPages.includes(to.path);
|
||||||
const auth = useUserInfoStore();
|
const auth = useUserInfoStore();
|
||||||
const token = useGetCookie("JWT-Authorization");
|
const token = useGetCookie("JWT-Authorization");
|
||||||
@ -116,7 +116,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
if ((authRequired && !token) || to.path === "/") {
|
if ((authRequired && !token) || to.path === "/") {
|
||||||
auth.user.token = "";
|
auth.user.token = "";
|
||||||
next({ path: "/login" });
|
next({ path: "/login" });
|
||||||
} else if (!authRequired && (to.path === "/login" || to.path === "/")) {
|
} else if (!authRequired) {
|
||||||
document.cookie = "JWT-Authorization=; Max-Age=0";
|
document.cookie = "JWT-Authorization=; Max-Age=0";
|
||||||
document.cookie = "user_name=; Max-Age=0";
|
document.cookie = "user_name=; Max-Age=0";
|
||||||
auth.user.token = "";
|
auth.user.token = "";
|
||||||
|
@ -4,7 +4,6 @@ import { ref } from "vue";
|
|||||||
const useUserInfoStore = defineStore("userInfo", () => {
|
const useUserInfoStore = defineStore("userInfo", () => {
|
||||||
const user = ref({
|
const user = ref({
|
||||||
token: "",
|
token: "",
|
||||||
expires: 0,
|
|
||||||
user_name:"",
|
user_name:"",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,9 +51,10 @@ watch(
|
|||||||
if (intervalId) {
|
if (intervalId) {
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
}
|
}
|
||||||
|
// 每小時呼叫一次
|
||||||
intervalId = setInterval(() => {
|
intervalId = setInterval(() => {
|
||||||
getEnergyCostData(params);
|
getEnergyCostData(params);
|
||||||
}, 3600000);
|
}, 60 * 60 * 1000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true, deep: true }
|
{ immediate: true, deep: true }
|
||||||
@ -91,13 +92,10 @@ onUnmounted(() => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full xl:w-1/4 mt-2">
|
<div class="w-full xl:w-1/4 mt-2">
|
||||||
<ElecRank :energyCostData="energyCostData" />
|
<ElecRank />
|
||||||
<ElecTrends
|
<ElecTrends
|
||||||
:formState="formState"
|
|
||||||
:energyCostData="energyCostData"
|
|
||||||
:getEnergyCostData="getEnergyCostData"
|
|
||||||
/>
|
/>
|
||||||
<ElecCompare :energyCostData="energyCostData" />
|
<ElecCompare />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,69 +1,22 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch, computed } from "vue";
|
import { ref, onMounted, watch, computed, onUnmounted } from "vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
|
import { getSystemEnergyCostGrowth } from "@/apis/headquarters";
|
||||||
import BarChart from "@/components/chart/BarChart.vue";
|
import BarChart from "@/components/chart/BarChart.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const { locale, t } = useI18n();
|
const { locale, t } = useI18n();
|
||||||
|
|
||||||
// 假資料
|
const energyCostGrowthData = ref({ day: [], week: [], month: [], year: [] });
|
||||||
const fakeEnergyData = ref({
|
|
||||||
buildings: [
|
|
||||||
{
|
|
||||||
name: "A棟",
|
|
||||||
today: 100,
|
|
||||||
yesterday: 90,
|
|
||||||
week: 500,
|
|
||||||
lastWeek: 450,
|
|
||||||
month: 2000,
|
|
||||||
lastMonth: 1800,
|
|
||||||
year: 24000,
|
|
||||||
lastYear: 22000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "B棟",
|
|
||||||
today: 120,
|
|
||||||
yesterday: 110,
|
|
||||||
week: 600,
|
|
||||||
lastWeek: 550,
|
|
||||||
month: 2400,
|
|
||||||
lastMonth: 2200,
|
|
||||||
year: 28000,
|
|
||||||
lastYear: 26000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "C棟",
|
|
||||||
today: 80,
|
|
||||||
yesterday: 70,
|
|
||||||
week: 400,
|
|
||||||
lastWeek: 350,
|
|
||||||
month: 1600,
|
|
||||||
lastMonth: 1400,
|
|
||||||
year: 19000,
|
|
||||||
lastYear: 17000,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "D棟",
|
|
||||||
today: 110,
|
|
||||||
yesterday: 100,
|
|
||||||
week: 550,
|
|
||||||
lastWeek: 500,
|
|
||||||
month: 2200,
|
|
||||||
lastMonth: 2000,
|
|
||||||
year: 26000,
|
|
||||||
lastYear: 24000,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const chartData = ref([]);
|
const chartData = ref([]);
|
||||||
const currentType = ref({
|
const currentType = ref({
|
||||||
name: "today",
|
name: "day",
|
||||||
});
|
});
|
||||||
const energyTypeList = ref([
|
const energyTypeList = ref([
|
||||||
{
|
{
|
||||||
title: t("dashboard.daily_relative_change"),
|
title: t("dashboard.daily_relative_change"),
|
||||||
key: "today",
|
key: "day",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("dashboard.weekly_relative_change"),
|
title: t("dashboard.weekly_relative_change"),
|
||||||
@ -78,10 +31,10 @@ const energyTypeList = ref([
|
|||||||
key: "year",
|
key: "year",
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
let intervalId = null;
|
||||||
const labels = computed(() => {
|
const labels = computed(() => {
|
||||||
switch (currentType.value.name) {
|
switch (currentType.value.name) {
|
||||||
case "today":
|
case "day":
|
||||||
return [t("dashboard.today"), t("dashboard.yesterday")];
|
return [t("dashboard.today"), t("dashboard.yesterday")];
|
||||||
case "week":
|
case "week":
|
||||||
return [t("dashboard.this_week"), t("dashboard.last_week")];
|
return [t("dashboard.this_week"), t("dashboard.last_week")];
|
||||||
@ -106,7 +59,7 @@ const barChartOptions = computed(() => ({
|
|||||||
left: "-10%",
|
left: "-10%",
|
||||||
right: "1%",
|
right: "1%",
|
||||||
bottom: "3%",
|
bottom: "3%",
|
||||||
top: "4%",
|
top: "10%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
@ -208,9 +161,7 @@ const barChartOptions = computed(() => ({
|
|||||||
let tooltipText = `<div>${params[0].axisValueLabel}</div>`;
|
let tooltipText = `<div>${params[0].axisValueLabel}</div>`;
|
||||||
const filteredParams = params.filter((item) => item.seriesType === "bar");
|
const filteredParams = params.filter((item) => item.seriesType === "bar");
|
||||||
filteredParams.forEach((item) => {
|
filteredParams.forEach((item) => {
|
||||||
tooltipText += `<div>${item.marker} ${
|
tooltipText += `<div>${item.marker} ${item.value}</div>`;
|
||||||
item.value ? item.value : "-"
|
|
||||||
}</div>`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return tooltipText;
|
return tooltipText;
|
||||||
@ -218,54 +169,58 @@ const barChartOptions = computed(() => ({
|
|||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
function updateChartData() {
|
async function fetchEnergyCostGrowth() {
|
||||||
// 從 fakeEnergyData 提取資料
|
try {
|
||||||
chartData.value = fakeEnergyData.value.buildings.map((building) => {
|
const res = await getSystemEnergyCostGrowth();
|
||||||
let currentKey = currentType.value.name;
|
energyCostGrowthData.value = res.data || {
|
||||||
let lastKey;
|
day: [],
|
||||||
|
week: [],
|
||||||
switch (currentType.value.name) {
|
month: [],
|
||||||
case "today":
|
year: [],
|
||||||
lastKey = "yesterday";
|
|
||||||
break;
|
|
||||||
case "week":
|
|
||||||
lastKey = "lastWeek";
|
|
||||||
break;
|
|
||||||
case "month":
|
|
||||||
lastKey = "lastMonth";
|
|
||||||
break;
|
|
||||||
case "year":
|
|
||||||
lastKey = "lastYear";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
lastKey = "yesterday";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: building.name,
|
|
||||||
current: building[currentKey],
|
|
||||||
last: building[lastKey],
|
|
||||||
difference: building[currentKey] - building[lastKey],
|
|
||||||
};
|
};
|
||||||
});
|
updateChartData();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching energy cost growth:", error);
|
||||||
|
energyCostGrowthData.value = { day: [], week: [], month: [], year: [] };
|
||||||
|
chartData.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateChartData() {
|
||||||
|
const list = energyCostGrowthData.value[currentType.value.name] || [];
|
||||||
|
chartData.value = list.map((item) => ({
|
||||||
|
name: item.name,
|
||||||
|
current: item.current,
|
||||||
|
last: item.last,
|
||||||
|
difference: ((item.current ?? 0) - (item.last ?? 0)).toFixed(2),
|
||||||
|
percentage: item.percentage,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 watch 監聽 fakeEnergyData 的變化
|
|
||||||
watch(
|
watch(
|
||||||
() => [fakeEnergyData.value, currentType.value],
|
() => currentType.value.name,
|
||||||
() => {
|
(newValue) => {
|
||||||
updateChartData();
|
if (newValue) {
|
||||||
|
updateChartData();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true } // 立即執行一次,確保初始資料載入
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 监听 currentType 的变化
|
onMounted(() => {
|
||||||
watch(currentType, () => {
|
fetchEnergyCostGrowth();
|
||||||
updateChartData();
|
if (intervalId) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
}
|
||||||
|
intervalId = setInterval(() => {
|
||||||
|
fetchEnergyCostGrowth();
|
||||||
|
}, 60 * 60 * 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(locale, () => {
|
onUnmounted(() => {
|
||||||
updateChartData();
|
clearInterval(intervalId);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@ -301,7 +256,8 @@ watch(locale, () => {
|
|||||||
<div
|
<div
|
||||||
v-for="(data, index) in chartData"
|
v-for="(data, index) in chartData"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="w-1/4 text-center mx-1"
|
class="text-center mx-1"
|
||||||
|
:style="{ width: 100 / chartData.length + '%' }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="text-xs bg-cyan-900 p-1 border border-cyan-100 border-opacity-20"
|
class="text-xs bg-cyan-900 p-1 border border-cyan-100 border-opacity-20"
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch, computed, onUnmounted } from "vue";
|
||||||
|
import { getSystemEnergyCostRank } from "@/apis/headquarters";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
|
|
||||||
|
const store = useBuildingStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const props = defineProps({
|
const energyCostData = ref({});
|
||||||
energyCostData: {
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const energyTypeList = ref([
|
const energyTypeList = ref([
|
||||||
{
|
{
|
||||||
title: t("dashboard.today_energy_consumption"),
|
title: t("dashboard.today_energy_consumption"),
|
||||||
key: "today",
|
key: "day",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("dashboard.this_month_energy_consumption"),
|
title: t("dashboard.this_month_energy_consumption"),
|
||||||
@ -23,17 +21,48 @@ const energyTypeList = ref([
|
|||||||
const currentEnergyType = ref({
|
const currentEnergyType = ref({
|
||||||
name: "month",
|
name: "month",
|
||||||
});
|
});
|
||||||
|
let intervalId = null;
|
||||||
|
|
||||||
// 取得當前能耗資料
|
const currentEnergyData = computed(() => {
|
||||||
const getCurrentEnergyData = () => {
|
if (!energyCostData.value) {
|
||||||
if (!props.energyCostData || !props.energyCostData.rank) {
|
return [];
|
||||||
return []; // 或者返回一些默认值
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentEnergyType.value.name === "month"
|
return currentEnergyType.value.name === "month"
|
||||||
? props.energyCostData?.rank.month || []
|
? energyCostData.value?.month || []
|
||||||
: props.energyCostData?.rank.day || [];
|
: 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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -62,7 +91,7 @@ const getCurrentEnergyData = () => {
|
|||||||
<table class="table table-sm text-center">
|
<table class="table table-sm text-center">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr
|
<tr
|
||||||
v-for="(item, index) in getCurrentEnergyData()"
|
v-for="(item, index) in currentEnergyData"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="[
|
:class="[
|
||||||
{ 'text-red-300': index + 1 === 1 },
|
{ 'text-red-300': index + 1 === 1 },
|
||||||
@ -71,13 +100,15 @@ const getCurrentEnergyData = () => {
|
|||||||
{ 'text-teal-300': index + 1 > 3 },
|
{ 'text-teal-300': index + 1 > 3 },
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<td class="flex items-center">
|
<td class="px-0 align-top">
|
||||||
<font-awesome-icon :icon="['fas', 'crown']" class="me-1" />{{
|
<p class="flex items-center">
|
||||||
index + 1
|
<font-awesome-icon :icon="['fas', 'crown']" class="me-1" />
|
||||||
}}
|
{{ index + 1 }}
|
||||||
</td>
|
</p>
|
||||||
<td>{{ item.name }}</td>
|
</td>
|
||||||
<td>{{ item.value }}</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>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from "vue";
|
import { ref, onMounted, watch, onUnmounted } from "vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
|
import { getSystemEnergyCostTrend } from "@/apis/headquarters";
|
||||||
import BarChart from "@/components/chart/BarChart.vue";
|
import BarChart from "@/components/chart/BarChart.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
@ -9,29 +10,12 @@ import useBuildingStore from "@/stores/useBuildingStore";
|
|||||||
const storeBuild = useBuildingStore();
|
const storeBuild = useBuildingStore();
|
||||||
const { t } = useI18n();
|
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 chartData = ref([]);
|
||||||
const buildingList = ref([]);
|
const buildingList = ref([]);
|
||||||
const floorList = ref([]);
|
const energyCostData = ref([]);
|
||||||
const deptList = ref([]);
|
|
||||||
const weekComparisonOption = ref({});
|
const weekComparisonOption = ref({});
|
||||||
const currentType = ref({
|
const currentType = ref({});
|
||||||
name: "all",
|
let intervalId = null;
|
||||||
});
|
|
||||||
// 生成柱狀圖的 option
|
// 生成柱狀圖的 option
|
||||||
const generateCylinderChartOption = (data) => {
|
const generateCylinderChartOption = (data) => {
|
||||||
const barWidth = 15;
|
const barWidth = 15;
|
||||||
@ -113,42 +97,38 @@ const generateCylinderChartOption = (data) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const processEnergyData = () => {
|
const processEnergyData = async () => {
|
||||||
if (!props.energyCostData || !props.energyCostData.trend) {
|
try {
|
||||||
chartData.value = [];
|
const res = await getSystemEnergyCostTrend({
|
||||||
|
building_ids: [currentType.value.name],
|
||||||
|
});
|
||||||
|
energyCostData.value = res.data.trend || [];
|
||||||
|
if (!energyCostData.value || energyCostData.value.length === 0) {
|
||||||
|
chartData.value = [];
|
||||||
|
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dailyData = [...energyCostData.value].sort(
|
||||||
|
(a, b) => new Date(a.time) - new Date(b.time)
|
||||||
|
);
|
||||||
|
chartData.value = dailyData.map((item) => ({
|
||||||
|
date: dayjs(item.time).format("MM/DD"),
|
||||||
|
energy: item.value,
|
||||||
|
}));
|
||||||
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
weekComparisonOption.value = generateCylinderChartOption(chartData.value);
|
||||||
return;
|
} catch (error) {
|
||||||
|
console.error("Error fetching energy cost trend:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dailyData = [...props.energyCostData.trend].sort(
|
|
||||||
(a, b) => new Date(a.time) - new Date(b.time)
|
|
||||||
);
|
|
||||||
|
|
||||||
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(
|
watch(
|
||||||
() => storeBuild.buildings,
|
() => storeBuild.buildings,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
|
currentType.value = {
|
||||||
|
name: newValue[0]?.building_guid || "all",
|
||||||
|
};
|
||||||
buildingList.value = [
|
buildingList.value = [
|
||||||
{
|
|
||||||
title: "All",
|
|
||||||
key: "all",
|
|
||||||
},
|
|
||||||
...newValue.map((building) => ({
|
...newValue.map((building) => ({
|
||||||
title: building.full_name,
|
title: building.full_name,
|
||||||
key: building.building_guid,
|
key: building.building_guid,
|
||||||
@ -161,42 +141,28 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 監聽 currentType 變化時重新取得資料
|
||||||
watch(
|
watch(
|
||||||
() => storeBuild.floorList,
|
() => currentType.value.name,
|
||||||
(newValue) => {
|
(newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
|
processEnergyData();
|
||||||
|
if (intervalId) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
}
|
||||||
|
intervalId = setInterval(() => {
|
||||||
|
processEnergyData();
|
||||||
|
}, 60 * 60 * 1000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
floorList.value = [
|
onUnmounted(() => {
|
||||||
{
|
clearInterval(intervalId);
|
||||||
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -207,7 +173,7 @@ watch(
|
|||||||
</h2>
|
</h2>
|
||||||
<Select
|
<Select
|
||||||
:value="currentType"
|
:value="currentType"
|
||||||
class="w-auto my-2"
|
class="w-[8.5rem] my-2"
|
||||||
selectClass="border-info focus-within:border-info btn-xs text-xs"
|
selectClass="border-info focus-within:border-info btn-xs text-xs"
|
||||||
name="name"
|
name="name"
|
||||||
Attribute="title"
|
Attribute="title"
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, watch, onUnmounted } from "vue";
|
import { ref, computed, watch, onUnmounted } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import { getAlarmOperationInfo } from "@/apis/dashboard";
|
import { getSystemStatus } from "@/apis/headquarters";
|
||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
// import DashboardSysProgressModal from "./DashboardSysProgressModal.vue";
|
import SysProgressModal from "./SysProgressModal.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -16,17 +16,27 @@ const equipmentData = ref({
|
|||||||
const modalData = ref({});
|
const modalData = ref({});
|
||||||
let intervalId = null;
|
let intervalId = null;
|
||||||
|
|
||||||
|
const openModal = (item) => {
|
||||||
|
modalData.value = item;
|
||||||
|
system_status_modal.showModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onCancel = () => {
|
||||||
|
modalData.value = {};
|
||||||
|
system_status_modal.close();
|
||||||
|
};
|
||||||
|
|
||||||
const getAlarmsInfos = async () => {
|
const getAlarmsInfos = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await getAlarmOperationInfo(
|
const res = await getSystemStatus({
|
||||||
store.selectedBuilding.building_guid
|
building_ids: store.buildings.map((building) => building.building_guid),
|
||||||
);
|
});
|
||||||
const apiData = res.data;
|
const apiData = res.data;
|
||||||
|
|
||||||
// 轉換 equipmentData 的資料格式
|
// 轉換 equipmentData 的資料格式
|
||||||
if (apiData && apiData.alarm) {
|
if (apiData && apiData.alarm) {
|
||||||
equipmentData.value.items = apiData.alarm.map((item) => ({
|
equipmentData.value.items = apiData.alarm.map((item) => ({
|
||||||
label: item.name,
|
label: item.system_name,
|
||||||
online: item.online || 0,
|
online: item.online || 0,
|
||||||
offline: item.offline || 0,
|
offline: item.offline || 0,
|
||||||
alarm: item.alarm || 0,
|
alarm: item.alarm || 0,
|
||||||
@ -38,7 +48,7 @@ const getAlarmsInfos = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => store.selectedBuilding,
|
() => store.buildings,
|
||||||
(newBuilding) => {
|
(newBuilding) => {
|
||||||
if (newBuilding) {
|
if (newBuilding) {
|
||||||
getAlarmsInfos();
|
getAlarmsInfos();
|
||||||
@ -60,44 +70,45 @@ onUnmounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<!-- <DashboardSysProgressModal :onCancel="onCancel" :modalData="modalData" /> -->
|
<SysProgressModal :onCancel="onCancel" :modalData="modalData" />
|
||||||
<div class="w-full state-box-col relative">
|
<div class="w-full state-box-col relative">
|
||||||
<div class="state-box">
|
<div class="state-box">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<img class="state-title01" src="@ASSET/img/state-title01.svg" />
|
<img class="state-title01" src="@ASSET/img/state-title01.svg" />
|
||||||
<span class="">{{ equipmentData.title }}</span>
|
<span class="">{{ equipmentData.title }}</span>
|
||||||
<img class="state-title02" src="@ASSET/img/state-title02.svg" />
|
<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.items"
|
|
||||||
:key="index"
|
|
||||||
class="border-cyan-400 cursor-pointer hover:text-info"
|
|
||||||
>
|
|
||||||
<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>
|
||||||
|
<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.items"
|
||||||
|
: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>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
132
src/views/headquarters/components/SysProgressModal.vue
Normal file
132
src/views/headquarters/components/SysProgressModal.vue
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, defineProps, inject, watch } from "vue";
|
||||||
|
import useActiveBtn from "@/hooks/useActiveBtn";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const props = defineProps({
|
||||||
|
onCancel: Function,
|
||||||
|
modalData: Object,
|
||||||
|
});
|
||||||
|
const { items, changeActiveBtn, setItems, selectedBtn } = useActiveBtn();
|
||||||
|
const detailData = ref([]);
|
||||||
|
onMounted(() => {
|
||||||
|
setItems([
|
||||||
|
{
|
||||||
|
title: t("alert.online"),
|
||||||
|
key: "online",
|
||||||
|
active: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("alert.offline"),
|
||||||
|
key: "offline",
|
||||||
|
active: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("alert.alarm"),
|
||||||
|
key: "alarm",
|
||||||
|
active: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(selectedBtn, (newVal, oldVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
detailData.value = props.modalData[newVal.key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modalData,
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
changeActiveBtn(items.value[0]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal id="system_status_modal" :onCancel="onCancel" :width="600">
|
||||||
|
<template #modalTitle>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<ButtonGroup
|
||||||
|
:items="items"
|
||||||
|
:withLine="true"
|
||||||
|
className="btn-sm"
|
||||||
|
:onclick="
|
||||||
|
(e, item) => {
|
||||||
|
changeActiveBtn(item);
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="link"
|
||||||
|
class="btn-link btn-text-without-border px-2"
|
||||||
|
@click="onCancel"
|
||||||
|
>
|
||||||
|
<font-awesome-icon :icon="['fas', 'times']" class="text-[#a5abb1]" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #modalContent>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table text-base mt-5">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th
|
||||||
|
class="text-base border text-white text-center bg-cyan-600 bg-opacity-30"
|
||||||
|
>
|
||||||
|
{{ $t("table.serial_number") }}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="text-base border text-white text-center bg-cyan-600 bg-opacity-30"
|
||||||
|
>
|
||||||
|
{{ $t("history.building_name") }}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="text-base border text-white text-center bg-cyan-600 bg-opacity-30"
|
||||||
|
>
|
||||||
|
{{ $t("table.name") }}
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
class="text-base border text-white text-center bg-cyan-600 bg-opacity-30"
|
||||||
|
>
|
||||||
|
{{ $t("table.time") }}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr
|
||||||
|
v-if="detailData?.length > 0"
|
||||||
|
v-for="(equipment, index) in detailData"
|
||||||
|
:key="index"
|
||||||
|
class="hover:bg-gray-700"
|
||||||
|
>
|
||||||
|
<td class="border text-white text-center">
|
||||||
|
{{ index + 1 }}
|
||||||
|
</td>
|
||||||
|
<td class="border text-white text-center">
|
||||||
|
{{ equipment.building_name }}
|
||||||
|
</td>
|
||||||
|
<td class="border text-white text-center">
|
||||||
|
{{ equipment.name }}
|
||||||
|
</td>
|
||||||
|
<td class="border text-white text-center">
|
||||||
|
{{ equipment.time || "-" }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-else>
|
||||||
|
<td colspan="4" class="border text-white text-center">
|
||||||
|
{{ $t("table.no_data") }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
@ -37,7 +37,7 @@ const doLogin = async () => {
|
|||||||
const res = await Login(value);
|
const res = await Login(value);
|
||||||
if (res.isSuccess) {
|
if (res.isSuccess) {
|
||||||
store.user = res.data;
|
store.user = res.data;
|
||||||
localStorage.setItem("CviBuildingList", JSON.stringify(res.data.buildingIdList));
|
localStorage.setItem("CviBuildingList", JSON.stringify(res.data.building_infos));
|
||||||
router.replace({ path: "/dashboard" });
|
router.replace({ path: "/dashboard" });
|
||||||
} else {
|
} else {
|
||||||
openToast("error", res.msg);
|
openToast("error", res.msg);
|
||||||
|
Loading…
Reference in New Issue
Block a user