Merge remote-tracking branch 'origin/main' into feature/system

This commit is contained in:
JouChun 2024-10-16 15:30:05 -04:00
commit 355fc12499
28 changed files with 559 additions and 281 deletions

View File

@ -1,3 +1,3 @@
VITE_API_BASEURL = "http://192.168.0.206:8060"
VITE_FILE_API_BASEURL = "http://192.168.0.206:8088"
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
VITE_FILE_API_BASEURL = "https://ibms-cvilux.production.mjmtech.com.tw"
VITE_FORGE_BASEURL = "http://localhost:5173"

View File

@ -1,3 +1,3 @@
VITE_API_BASEURL = "http://192.168.0.206:8060"
VITE_FILE_API_BASEURL = "http://192.168.0.206:8088"
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
VITE_FILE_API_BASEURL = "https://ibms-cvilux.production.mjmtech.com.tw"
VITE_FORGE_BASEURL = "http://202.39.218.221:8080/file/netzero"

View File

@ -79,8 +79,8 @@ export const getAlarmMemberList = async () => {
});
};
export const getNoticeList = async () => {
const res = await instance.post(GET_NOTICE_LIST_API, {});
export const getNoticeList = async (lang) => {
const res = await instance.post(GET_NOTICE_LIST_API, { lang });
return apihandler(res.code, res.data, {
msg: res.msg,

View File

@ -16,8 +16,10 @@ export const getBuildings = async () => {
});
};
export const getAuth = async () => {
const res = await instance.post(GET_AUTHPAGE_API);
export const getAuth = async (lang) => {
const res = await instance.post(GET_AUTHPAGE_API, {
lang,
});
return apihandler(res.code, res.data, {
msg: res.msg,
code: res.code,

View File

@ -24,13 +24,13 @@ const toggleErrIcon = () => {
v-if="!showErr"
:icon="['fas', 'comment-dots']"
size="2x"
class="text-white menu-icon"
class="text-white w-10 m-auto"
/>
<font-awesome-icon
v-else
:icon="['fas', 'comment-slash']"
size="2x"
class="text-white menu-icon"
class="text-white w-10 m-auto"
/>
<span class="text-white"> {{ $t("alarm.title") }}</span>
</label>

View File

@ -2,6 +2,8 @@
import { defineProps, ref, computed, inject, watch } from "vue";
import { twMerge } from "tailwind-merge";
import { data } from "autoprefixer";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
/* -------------------------------------------------------------
> 6 => 會有 input 跳頁且前三後三顯示
---------------------------------------------------------------- */
@ -117,7 +119,7 @@ const pageInput = computed(() => {
v-if="totalPage < 6"
class="absolute -bottom-8 -translate-x-1/2 text-base text-center"
>
{{ dataSource.length }} </span
{{ dataSource.length }} {{ $t("table.in_otal") }}</span
>
<label
v-if="totalPage > 6"
@ -127,7 +129,7 @@ const pageInput = computed(() => {
type="text"
maxlength="6"
class="bg-transparent h-full w-20 font-extrabold italic text-lg"
placeholder="跳至"
:placeholder="t('table.skip_to')"
:value="pageInput"
@change="
(e) => {
@ -143,7 +145,7 @@ const pageInput = computed(() => {
<span
class="w-full text-center absolute -bottom-8 left-1/2 -translate-x-1/2 text-base"
>
{{ totalItems || dataSource.length }} </span
{{ totalItems || dataSource.length }} {{ $t("table.in_otal") }}</span
>
</label>
<ul

View File

@ -4,6 +4,8 @@ import { computed, defineProps, provide, ref, watch } from "vue";
import Pagination from "@/components/customUI/Pagination.vue";
import Checkbox from "@/components/customUI/Checkbox.vue";
import dayjs from "dayjs";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
/*
column={
title,key,class, width, filter:Boolean, sort:Boolean
@ -246,14 +248,14 @@ watch(
<input
type="reset"
class="btn btn-sm text-white btn-error"
value="重置"
:value="t('button.reset')"
@click="() => onFilter(column.key, true)"
/>
<button
class="btn btn-sm btn-success"
@click.stop.prevent="() => onFilter(column.key)"
>
確定
{{ $t("button.submit") }}
</button>
</div>
</div>
@ -270,7 +272,7 @@ watch(
</td>
</tr>
<tr v-else-if="currentDataSource.length == 0">
<td :colspan="columns.length">表中數據為空</td>
<td :colspan="columns.length">{{ $t("table.no_data") }}</td>
</tr>
<template v-else :sort="sortRule">
<tr

View File

@ -1,7 +1,8 @@
<script setup>
import { ref, defineProps, watch, onMounted } from "vue";
import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n";
const { t } = useI18n();
const props = defineProps({
name: String,
fileList: Array,
@ -262,8 +263,8 @@ const revokeURL = (src) => {
<div>
<font-awesome-icon size="2x" :icon="['fas', 'cloud-upload-alt']" />
</div>
<p class="text-2xl my-2">選擇一個文件或拖放到這裡</p>
<p class="mb-0 col-grey">檔案不超過 10MB</p>
<p class="text-2xl my-2">{{ $t("upload.title") }}</p>
<p class="mb-0 col-grey">{{ $t("upload.description") }}</p>
</div>
</div>

View File

@ -6,8 +6,10 @@ import Logo from "@/assets/img/logo.svg";
import useGetCookie from "@/hooks/useGetCookie";
import AlarmDrawer from "@/components/alarm/AlarmDrawer.vue";
import NavbarLang from "./NavbarLang.vue";
import { twMerge } from "tailwind-merge";
const user = ref("");
const menuShow = ref(true);
onMounted(() => {
const name = useGetCookie("niagara_userid");
@ -16,43 +18,51 @@ onMounted(() => {
}
});
const toggleMenu = () => {
menuShow.value = !menuShow.value;
};
const src = import.meta.env.MODE === "production" ? "./logo.svg" : Logo;
</script>
<template>
<header class="navbar bg-dark text-success w-full relative z-50">
<header class="navbar bg-dark text-light-info w-full relative z-50">
<div class="navbar-start">
<div class="dropdown">
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</div>
<ul
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52"
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden" @click="toggleMenu">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<NavbarItem />
</ul>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</div>
<router-link to="/dashboard" class="rounded-lg pl-4 text-2xl font-bold text-white flex items-center">
<router-link
to="/dashboard"
class="rounded-lg pl-4 text-2xl font-bold text-white flex items-center"
>
<img :src="src" alt="logo" class="w-8 me-1" />
CviLux Group
</router-link>
<NavbarBuilding />
</div>
<div class="navbar-center hidden lg:flex">
<div
:class="
twMerge(
'navbar-center flex absolute lg:relative top-full bg-dark',
menuShow ? 'block' : 'hidden'
)
"
>
<NavbarItem />
</div>
<div class="navbar-end mr-4">
@ -73,7 +83,7 @@ const src = import.meta.env.MODE === "production" ? "./logo.svg" : Logo;
<font-awesome-icon
:icon="['fas', 'user-circle']"
size="2x"
class="text-white menu-icon"
class="text-white w-10 m-auto"
/>
<span class="text-white"> {{ user || "webUser" }}</span>
</button>
@ -82,10 +92,11 @@ const src = import.meta.env.MODE === "production" ? "./logo.svg" : Logo;
class="dropdown-content translate-y-2 z-[100] menu py-3 shadow rounded w-32 bg-[#4c625e] border text-center"
>
<li class="text-white">
<a
href="/logout"
<router-link
to="logout"
type="link"
class="flex flex-col justify-center items-center"
>{{ $t("sign_out") }}</a
>{{ $t("sign_out") }}</router-link
>
</li>
</ul>
@ -98,11 +109,11 @@ const src = import.meta.env.MODE === "production" ? "./logo.svg" : Logo;
<style lang="css">
.sub-drawer {
@apply bg-dark bg-opacity-80 shadow-xl !important;
@apply bg-dark bg-opacity-90 shadow-xl !important;
}
/**menu**/
.menu-box {
@apply flex justify-center;
@apply flex flex-wrap justify-center ;
position: relative;
z-index: 0;
}
@ -130,11 +141,6 @@ const src = import.meta.env.MODE === "production" ? "./logo.svg" : Logo;
z-index: 0;
}
.menu-icon {
width: 40px;
margin: auto;
}
.menu-box .btn-group span {
color: #fff;
display: block;

View File

@ -4,21 +4,23 @@ import { AUTHPAGES } from "@/constant";
import { getAuth, getAllSysSidebar } from "@/apis/building";
import useBuildingStore from "@/stores/useBuildingStore";
import useUserInfoStore from "@/stores/useUserInfoStore";
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const store = useUserInfoStore();
const buildingStore = useBuildingStore();
const openKeys = ref([]); //
const iniFroList = async () => {
const res = await getAuth();
const res = await getAuth(locale.value);
store.updateAuthPage(
res.data.map((d) =>
AUTHPAGES.find(({ authCode }) => authCode === d.authCode)
? {
...d,
...AUTHPAGES.find(({ authCode }) => authCode === d.authCode),
}
...d,
...AUTHPAGES.find(({ authCode }) => authCode === d.authCode),
}
: d
)
);
@ -41,20 +43,12 @@ const onClose = () => {
open.value = false;
};
const navigateToSub = (sub) => {
// buildingStore.selectedSystem = sub;
onClose()
// console.log("navigateToSub", sub);
// let pageAct = JSON.parse(sessionStorage.getItem("pageAct"));
// pageAct = {
// ...pageAct,
// sysMainTag: sub.main_system_tag,
// sysSubTag: sub.sub_system_tag,
// sysSubName: sub.full_name,
// };
// sessionStorage.setItem("lastPage", "systemMonitor");
// sessionStorage.setItem("pageAct", JSON.stringify(pageAct));
// window.location.href = "/file/index.html";
const handleOpenChange = (keys) => {
if (keys.length > 0) {
openKeys.value = [keys[keys.length - 1]]; //
} else {
openKeys.value = [];
}
};
watch(
@ -66,6 +60,10 @@ watch(
}
);
watch(locale, () => {
iniFroList();
});
onMounted(() => {
iniFroList();
});
@ -73,44 +71,106 @@ onMounted(() => {
<template>
<ul class="px-1 menu-box my-2">
<li class="flex flex-col items-center justify-center">
<router-link :to="{ name: 'dashboard' }" class="flex flex-col justify-center items-center btn-group text-white">
<font-awesome-icon :icon="['fas', 'home']" size="2x" class="menu-icon" />
首頁
<router-link
:to="{ name: 'dashboard' }"
class="flex flex-col justify-center items-center btn-group text-white"
>
<font-awesome-icon
:icon="['fas', 'home']"
size="2x"
class="w-10 m-auto"
/>
{{ $t("home") }}
</router-link>
</li>
<li v-for="page in authPages" class="flex flex-col items-center justify-center">
<a v-if="page.authCode === 'PF1'" @click="showDrawer"
class="flex flex-col justify-center items-center btn-group text-white cursor-pointer">
<font-awesome-icon :icon="['fas', page.icon]" size="2x" class="menu-icon" />
<li
v-for="page in authPages"
class="flex flex-col items-center justify-center"
>
<a
v-if="page.authCode === 'PF1'"
@click="showDrawer"
class="flex flex-col justify-center items-center btn-group text-white cursor-pointer"
>
<font-awesome-icon
:icon="['fas', page.icon]"
size="2x"
class="w-10 m-auto"
/>
{{ page.subName }}
</a>
<router-link v-else :to="page.navigate" type="link"
class="flex flex-col justify-center items-center btn-group text-white">
<font-awesome-icon :icon="['fas', page.icon]" size="2x" class="menu-icon" />
<router-link
v-else
:to="page.navigate"
type="link"
class="flex flex-col justify-center items-center btn-group text-white"
>
<font-awesome-icon
:icon="['fas', page.icon]"
size="2x"
class="w-10 m-auto"
/>
{{ page.subName }}
</router-link>
</li>
</ul>
<a-drawer :width="200" placement="left" :open="open" :closable="false" @close="onClose" class="sub-drawer"
:maskStyle="{ opacity: 0.5 }" :bodyStyle="{ paddingLeft: 0, paddingRight: 0 }">
<ul>
<li v-for="sub in buildingStore.subSys" :key="sub.sub_system_tag"
class="group text-xl text-center py-3 hover:bg-black" @click="() => navigateToSub(sub)">
<router-link
:to="{ name: 'sub_system', params: { main_system_id: sub.main_system_tag, sub_system_id: sub.sub_system_tag }, }"
type="link" class="group-hover:text-info">
{{ sub.full_name }}
</router-link>
</li>
</ul>
<a-drawer
:width="250"
placement="left"
:open="open"
:closable="false"
@close="onClose"
class="sub-drawer"
:maskStyle="{ opacity: 0 }"
:bodyStyle="{ paddingLeft: 0, paddingRight: 0 }"
>
<a-menu
mode="inline"
theme="dark"
class="text-lg bg-transparent"
:openKeys="openKeys"
@openChange="handleOpenChange"
>
<a-sub-menu
v-for="main in buildingStore.mainSubSys"
:key="main.main_system_tag"
:title="main.full_name"
>
<a-menu-item
v-for="sub in main.history_Sub_systems"
:key="sub.sub_system_tag"
@click="() => onClose()"
>
<router-link
:to="{
name: 'sub_system',
params: {
main_system_id: main.main_system_tag,
sub_system_id: sub.sub_system_tag,
},
}"
>
{{ sub.full_name }}
</router-link>
</a-menu-item>
</a-sub-menu>
</a-menu>
</a-drawer>
</template>
<style lang="css" scoped>
<style lang="scss" scoped>
.router-link-active.router-link-exact-active {
color: #93c0dc;
}
::v-deep .ant-menu-submenu-title:active {
background-color: #35759d !important;
}
::v-deep .ant-menu-item-selected {
background-color: #35759d !important;
a {
color: #fff !important;
}
}
</style>

View File

@ -3,12 +3,10 @@ import { useI18n } from "vue-i18n";
import { ref, onMounted } from "vue";
const { locale } = useI18n(); // 使 I18n
const language = ref(locale.value)
//
const toggleLanguage = (lang) => {
locale.value = lang;
localStorage.setItem("CviLanguage", lang);
language.value = lang;
};
</script>
@ -20,7 +18,7 @@ const toggleLanguage = (lang) => {
class="flex flex-col justify-center items-center btn-group"
>
<span
:class="`fi fi-${language} fis text-3xl rounded-full border-1 border-white`"
:class="`fi fi-${locale} fis text-3xl rounded-full border-1 border-white`"
></span>
<span class="text-white">{{ $t("language") }}</span>
</button>

View File

@ -1,9 +1,28 @@
{
"language": "简体中文",
"home": "首页",
"sign_out": "登出",
"log_in": "登入",
"account": "帐号",
"password": "密码",
"table": {
"no_data": "表中数据为空",
"in_otal": "笔资料",
"skip_to": "跳至"
},
"upload": {
"title": "选择一个文件或拖放到这里",
"description": "档案不超过 10MB"
},
"dashboard": {
"yesterday_today": "昨天/今天",
"elec_consumption_comparison": "用电量比较",
"today_electricity_consumption": "今日用电量",
"yesterday_electricity_consumption": "昨天用电量",
"this_last_week": "本周/上周",
"thisweek_electricity_consumption": "本周用电量",
"lastweek_electricity_consumption": "上周用电量"
},
"history": {
"title": "历史资料",
"building_name": "厂区",
@ -21,6 +40,23 @@
"end_date": "结束日期",
"end_time": "结束时间"
},
"energy": {
"elec_consumption": "用电即时分布",
"total_elec": "总用电",
"green_elec": "绿电",
"immediate_demand": "即时需量",
"average_demand": "平均需量",
"elec_bills": "今年电费累计(元)",
"interval_elec_charges": "区间电费(元)",
"year_carbon_emission": "今年碳排当量累计(公斤)",
"interval_carbon_emission": "区间碳排当量",
"year_elec_consumption": "今年用电度数(kWh)",
"interval_elec_consumption": "区间用电度数(kWh)",
"monthly_elec_consumption": "每月用电分析",
"monthly_carbon_emission_and_reduction": "每月碳排当量 (kgCO2e) 与减量目标",
"monthly_bill_power": "每月计费度数 (kWh)",
"interval_bill_degree": "区间计费度数"
},
"alarm": {
"title": "显示警告",
"notify": "异常通知",

View File

@ -1,9 +1,28 @@
{
"language": "繁體中文",
"home": "首頁",
"sign_out": "登出",
"log_in": "登入",
"account": "帳號",
"password": "密碼",
"table": {
"no_data": "表中數據為空",
"in_otal": "筆資料",
"skip_to": "跳至"
},
"upload": {
"title": "選擇一個文件或拖放到這裡",
"description": "檔案不超過 10MB"
},
"dashboard": {
"yesterday_today": "昨天/今天",
"elec_consumption_comparison":"用電量比較",
"today_electricity_consumption":"今日用電量",
"yesterday_electricity_consumption":"昨天用電量",
"this_last_week":"本週/上週",
"thisweek_electricity_consumption":"本周用電量",
"lastweek_electricity_consumption":"上週用電量"
},
"history": {
"title": "歷史資料",
"building_name": "廠區",
@ -21,6 +40,23 @@
"end_date": "結束日期",
"end_time": "結束時間"
},
"energy": {
"elec_consumption": "用電即時分佈",
"total_elec": "總用電",
"green_elec": "綠電",
"immediate_demand": "即時需量",
"average_demand": "平均需量",
"elec_bills": "今年電費累計(元)",
"interval_elec_charges": "區間電費(元)",
"year_carbon_emission": "今年碳排當量累計(公斤)",
"interval_carbon_emission": "區間碳排當量",
"year_elec_consumption": "今年用電度數(kWh)",
"interval_elec_consumption": "區間用電度數(kWh)",
"monthly_elec_consumption": "每月用電分析",
"monthly_carbon_emission_and_reduction": "每月碳排當量 (kgCO2e) 與減量目標",
"monthly_bill_power": "每月計費度數 (kWh)",
"interval_bill_degree": "區間計費度數"
},
"alarm": {
"title": "顯示警告",
"notify": "異常通知",

View File

@ -1,9 +1,19 @@
{
"language": "English",
"home": "Home",
"sign_out": "Sign out",
"log_in": "Log in",
"account": "Account",
"password": "Password",
"table": {
"no_data": "No data",
"in_otal": "items in total",
"skip_to": "Skip to"
},
"upload": {
"title": "Select a file or drag and drop here",
"description": "File size cannot exceed 10MB"
},
"history": {
"title": "Historical Data",
"building_name": "Building",
@ -21,6 +31,32 @@
"end_date": "End date",
"end_time": "End time"
},
"dashboard": {
"yesterday_today": "Yesterday / Today's",
"elec_consumption_comparison": "Electricity Consumption Comparison",
"today_electricity_consumption": "Todays electricity consumption",
"yesterday_electricity_consumption": "Yesterdays electricity consumption",
"this_last_week": "This Week's / Last Week's",
"thisweek_electricity_consumption": "This weeks electricity consumption",
"lastweek_electricity_consumption": "Last weeks electricity consumption"
},
"energy": {
"elec_consumption": "Real-time distribution of electricity consumption",
"total_elec": "Total electricity consumption",
"green_elec": "Green electricity",
"immediate_demand": "immediate demand",
"average_demand": "average demand",
"elec_bills": "Total electricity bills this year (yuan)",
"interval_elec_charges": "Interval electricity charges (yuan)",
"year_carbon_emission": "Cumulative carbon emission equivalent this year (kg)",
"interval_carbon_emission": "Interval carbon emission equivalent",
"year_elec_consumption": "This year's electricity consumption (kWh)",
"interval_elec_consumption": "Interval electricity consumption (kWh)",
"monthly_elec_consumption": "Monthly electricity consumption analysis",
"monthly_carbon_emission_and_reduction": "Monthly carbon emission equivalent (kgCO2e) and reduction target",
"monthly_bill_power": "Monthly billing power (kWh)",
"interval_bill_degree": "Interval billing degree"
},
"alarm": {
"title": "Warning",
"notify": "Notification",

View File

@ -40,6 +40,20 @@ import {
faFilePowerpoint,
faFileAlt,
faDatabase,
faBuilding,
faVideo,
faFan,
faTemperatureHigh,
faLightbulb,
faBolt,
faChargingStation,
faTint,
faWater,
faCarBattery,
faFireExtinguisher,
faDoorOpen,
faCar,
faWind
} from "@fortawesome/free-solid-svg-icons";
/* add icons to the library */
@ -81,6 +95,20 @@ library.add(
faFilePowerpoint,
faFileAlt,
faDatabase,
faBuilding,
faVideo,
faFan,
faTemperatureHigh,
faLightbulb,
faBolt,
faChargingStation,
faTint,
faWater,
faCarBattery,
faFireExtinguisher,
faDoorOpen,
faCar,
faWind
);
export default library;

View File

@ -94,6 +94,16 @@ const router = createRouter({
name: "mytestfile",
component: Test,
},
{
path: "/logout",
name: "logout",
beforeEnter: (to, from, next) => {
const auth = useUserInfoStore();
document.cookie = "JWT-Authorization=";
auth.user.token = "";
next({ path: "/login", replace: true });
},
},
],
});
@ -105,13 +115,6 @@ router.beforeEach(async (to, from, next) => {
const auth = useUserInfoStore();
const token = useGetCookie("JWT-Authorization");
if (location.pathname.includes("logoutConfirm")) {
document.cookie = "JWT-Authorization=";
auth.user.token = "";
// 清除 cookie token
next({ path: "/login" });
}
if ((authRequired && !token) || to.path === "/") {
auth.user.token = "";
next({ path: "/login" });

View File

@ -167,14 +167,14 @@ const onCancel = () => {
:options="floors"
:isBottomLabelExist="false"
>
<template #topLeft>{{ t("assetManagement.floor") }}</template>
<template #topLeft>{{ $t("assetManagement.floor") }}</template>
</Select>
<button
type="button"
class="btn btn-success mt-10 ml-5"
@click="openModal"
>
{{ t("assetManagement.add_floor") }}
{{ $t("assetManagement.add_floor") }}
</button>
</div>
<!-- <button type="button" class="btn btn-success mt-10">確認座標</button> -->
@ -195,7 +195,7 @@ const onCancel = () => {
v-if="!currentFloor?.floor_map_url"
class="absolute top-0 left-0 flex justify-center items-center min-h-[500px] w-full border border-stone-900 shadow-lg bg-sub-success bg-opacity-25 rounded-md"
>
<p class="text-2xl">{{ t("assetManagement.add_floor_text") }}</p>
<p class="text-2xl">{{ $t("assetManagement.add_floor_text") }}</p>
</div>
</div>
<Modal

View File

@ -2,15 +2,22 @@
import AlertSubList from "./AlertSubList.vue";
import AlertOutliersTable from "./AlertOutliersTable.vue";
import AlertNotifyTable from "./AlertNotifyTable.vue";
import { ref, provide, onMounted } from "vue";
import { ref, provide, onMounted, watch } from "vue";
import { getNoticeList } from "@/apis/alert";
import { useI18n } from "vue-i18n";
const { locale } = useI18n();
const noticeList = ref([]);
const NoticeListData = async () => {
const res = await getNoticeList();
const res = await getNoticeList(locale.value);
noticeList.value = res.data;
};
watch(locale, () => {
NoticeListData();
});
onMounted(() => {
NoticeListData();
});

View File

@ -1,111 +1,171 @@
<script setup>
import { ref } from "vue";
import { ref, onMounted } from "vue";
import * as echarts from "echarts";
import BarChart from "@/components/chart/BarChart.vue";
//
//
const yesterdayTodayData = {
data: {
categories: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
values: [
{
name: "Yesterday's electricity consumption",
value: [10, 10, 10, 10, 10, 20, 30, 80, 90, 70],
},
{
name: "Today's electricity consumption",
value: [8, 8, 8, 8, 8, 15, 25, 65, 75, 60],
},
],
},
};
//
const weekComparisonData = {
data: {
categories: ["週五", "週六", "週日", "週一", "週二", "週三", "週四"],
values: [
{
name: "Last week's electricity consumption",
value: [800, 150, 300, 750, 900, 900, 800],
},
{
name: "This week's electricity consumption",
value: [850, 200, 350, 850, 950, 950, 900],
},
],
},
};
// option legend
const generateChartOption = (categories, values) => ({
xAxis: {
type: "category",
data: categories,
axisLine: {
lineStyle: {
color: "#fff",
},
},
},
yAxis: {
type: "value",
axisLine: {
lineStyle: {
color: "#fff",
},
},
splitLine: {
lineStyle: {
color: "#ccc",
},
},
},
series: [
categories: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
values: [
{
name: values[0].name,
data: values[0].value,
type: "bar",
barWidth: "35%",
itemStyle: {
color: "#FFD700", //
},
name: "Today's electricity consumption",
value: [8, 8, 8, 8, 8, 15, 25, 65, 75, 60],
},
{
name: values[1].name,
data: values[1].value,
type: "bar",
barWidth: "35%",
itemStyle: {
color: "#00BFFF", //
},
name: "Yesterday's electricity consumption",
value: [10, 10, 10, 10, 10, 20, 30, 80, 90, 70],
},
],
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
};
//
const weekComparisonData = {
categories: ["週五", "週六", "週日", "週一", "週二", "週三", "週四"],
values: [
{
name: "This week's electricity consumption",
value: [850, 200, 350, 850, 950, 950, 900],
},
},
legend: {
show: false, // legend
},
});
{
name: "Last week's electricity consumption",
value: [800, 150, 300, 750, 900, 900, 800],
},
],
};
// option
const generateCylinderChartOption = (categories, values) => {
const barWidth = 15; //
return {
xAxis: {
type: "category",
data: categories,
axisLine: {
lineStyle: {
color: "#fff",
},
},
},
yAxis: {
type: "value",
axisLine: {
lineStyle: {
color: "#fff",
},
},
splitLine: {
lineStyle: {
color: "#ccc",
},
},
},
series: [
{
name: values[0].name,
type: "bar",
barWidth: barWidth,
data: values[0].value,
itemStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 1, //
y2: 0, //
colorStops: [
{ offset: 0, color: "#acd7e4" }, //
{ offset: 0.5, color: "#0ca9d4" }, //
{ offset: 1, color: "#acd7e4" }, //
],
},
},
},
{
name: values[1].name,
type: "bar",
barWidth: barWidth,
data: values[1].value,
itemStyle: {
color: {
type: "linear",
x: 0,
y: 0,
x2: 1, //
y2: 0, //
colorStops: [
{ offset: 0, color: "#fff6b3" }, //
{ offset: 0.5, color: "#ffe000" }, //
{ offset: 1, color: "#fff6b3" }, //
],
},
},
},
//
{
name: null,
type: "pictorialBar",
symbolSize: [barWidth, 5],
symbolOffset: [-9, -5],
symbolPosition: "end",
data: values[0].value,
z: 12,
itemStyle: {
color: "#0b86a7",
borderWidth: 10,
borderColor: "#fff",
borderType: "solid",
},
},
{
name: null,
type: "pictorialBar",
symbolSize: [barWidth, 5],
symbolOffset: [9, -5],
symbolPosition: "end",
data: values[1].value,
itemStyle: {
color: "#c3ae1a",
borderWidth: 10,
borderColor: "#fff",
borderType: "solid",
},
z: 12,
},
],
grid: {
left: "3%",
right: "3%",
bottom: "3%",
top: "15%",
containLabel: true,
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
formatter: function (params) {
// bar
const barData = params.filter((item) => item.seriesType === "bar");
return barData
.map((item) => `${item.seriesName}: ${item.data}`)
.join("<br/>");
},
},
legend: {
show: false, // legend
},
};
};
// option
const yesterdayTodayOption = generateChartOption(
yesterdayTodayData.data.categories,
yesterdayTodayData.data.values
const yesterdayTodayOption = generateCylinderChartOption(
yesterdayTodayData.categories,
yesterdayTodayData.values
);
const weekComparisonOption = generateChartOption(
weekComparisonData.data.categories,
weekComparisonData.data.values
const weekComparisonOption = generateCylinderChartOption(
weekComparisonData.categories,
weekComparisonData.values
);
</script>
@ -115,16 +175,18 @@ const weekComparisonOption = generateChartOption(
<div class="lg:w-1/2 w-full chart-data relative px-8 py-3">
<div class="flex flex-wrap items-center">
<h2 class="text-xs font-light w-1/2 relative">
Yesterday / Today's<br />Electricity Consumption Comparison (kWH)
{{ $t("dashboard.yesterday_today") }}<br />
{{ $t("dashboard.elec_consumption_comparison") }}
(kWH)
</h2>
<div class="w-[48%]">
<a href="#" class="text-con">
<img src="@ASSET/img/chart-title01.svg" />
<span>Todays electricity consumption</span>
<span>{{ $t("dashboard.today_electricity_consumption") }}</span>
</a>
<a href="#" class="text-con">
<img src="@ASSET/img/chart-title02.svg" />
<span>Yesterdays electricity consumption</span>
<span>{{ $t("dashboard.yesterday_electricity_consumption") }}</span>
</a>
</div>
</div>
@ -141,16 +203,18 @@ const weekComparisonOption = generateChartOption(
<div class="lg:w-1/2 w-full chart-data relative px-8 py-3">
<div class="flex flex-wrap items-center">
<h2 class="text-xs font-light w-1/2 relative">
This Week's / Last Week's <br />Electricity Consumption Comparison (kWH)
{{ $t("dashboard.this_last_week") }}<br />
{{ $t("dashboard.elec_consumption_comparison") }}
(kWH)
</h2>
<div class="w-[48%]">
<a href="#" class="text-con">
<img src="@ASSET/img/chart-title01.svg" />
<span>This weeks electricity consumption</span>
<span>{{ $t("dashboard.thisweek_electricity_consumption") }}</span>
</a>
<a href="#" class="text-con">
<img src="@ASSET/img/chart-title02.svg" />
<span>Last weeks electricity consumption</span>
<span>{{ $t("dashboard.lastweek_electricity_consumption") }}</span>
</a>
</div>
</div>

View File

@ -3,34 +3,22 @@ import { ref } from "vue";
//
const mockData = ref([
{ title: "Elevator system", icon: "EL", isError: false },
{ title: "CCTV system", icon: "C", isError: true },
{ title: "Emergency rescue system", icon: "P", isError: true },
{ title: "Air Conditioning System", icon: "M10", isError: false },
{ title: "Lighting system", icon: "L1", isError: false },
{ title: "Fire Equipment", icon: "F1", isError: false },
{ title: "Water supply system", icon: "W2", isError: false },
{
title: "Sewage and wastewater equipment",
icon: "P1",
isError: false,
},
{ title: "High voltage switchboard", icon: "E1", isError: false },
{ title: "Low voltage switchboard", icon: "E2", isError: false },
{ title: "Meter system", icon: "E4-1", isError: false },
{ title: "Emergency generator", icon: "E3", isError: false },
{ title: "Shutdown system", icon: "PSC", isError: false },
{ title: "Access control system", icon: "R", isError: false },
{
title: "Environmental sensing equipment",
icon: "M12",
isError: false,
},
{
title: "Air supply and exhaust system",
icon: "M5-2",
isError: false,
},
{ title: "Elevator system", icon: "building", isError: false },
{ title: "Air Conditioning System", icon: "fan", isError: false },
{ title: "Environmental sensing equipment", icon: "temperature-high", isError: false },
{ title: "Lighting system", icon: "lightbulb", isError: false },
{ title: "Meter system", icon: "bolt", isError: false },
{ title: "High voltage switchboard", icon: "charging-station", isError: false },
{ title: "Low voltage switchboard", icon: "charging-station", isError: false },
{ title: "Water supply system", icon: "tint", isError: false },
{ title: "Sewage and wastewater equipment", icon: "water", isError: false },
{ title: "Emergency generator", icon: "car-battery", isError: false },
{ title: "Fire Equipment", icon: "fire-extinguisher", isError: false },
{ title: "CCTV system", icon: "video", isError: true },
{ title: "Access control system", icon: "door-open", isError: false },
{ title: "Shutdown system", icon: "car", isError: false },
{ title: "Emergency rescue system", icon: "exclamation-triangle", isError: true },
{ title: "Air supply and exhaust system", icon: "wind", isError: false },
]);
</script>
@ -48,15 +36,11 @@ const mockData = ref([
<img v-else src="@ASSET/img/equipment-item-background04.svg" />
<div class="equipment-item">
<div class="w-20">
<img
class="w-14 p-2 m-auto"
:src="`./icon/${item.icon}.png`"
alt="icon"
/>
<div class="w-16">
<FontAwesomeIcon class="text-2xl mt-1 m-auto" :icon="['fas', item.icon]"></FontAwesomeIcon>
</div>
<div class="icon-text">
<div class="text-slate-300 text-xs">{{ item.title }}</div>
<div class="text-slate-300 text-sm">{{ item.title }}</div>
</div>
</div>
</div>
@ -68,7 +52,7 @@ const mockData = ref([
@apply flex items-center absolute top-1/2 w-[90%] left-0 right-0 m-auto text-center -translate-y-1/2;
}
.icon-text {
@apply text-start font-light p-1 relative z-20;
@apply w-52 text-start p-3 relative z-20;
}
.icon-text:before {
@apply absolute -left-3 top-0 bottom-0 m-auto h-10 w-5 z-10;

View File

@ -96,7 +96,9 @@ onMounted(() => {
<template>
<div class="bg-slate-800 p-3">
<div class="text-white mb-3 text-base">每月計費度數 (kWh)</div>
<div class="text-white mb-3 text-base">
{{ $t("energy.monthly_bill_power") }}
</div>
<div class="bar-box">
<BarChart
id="billing_degree_chart"

View File

@ -85,7 +85,7 @@ onMounted(() => {
<template>
<div class="bg-slate-800 p-3">
<div class="text-white mb-3 text-base">
每月碳排當量 (kgCO2e) 與減量目標
{{ $t("energy.monthly_carbon_emission_and_reduction") }}
</div>
<div class="bar-box">
<BarChart

View File

@ -36,7 +36,6 @@ const chartOption = {
label: {
position: "right",
fontSize: 12,
borderWidth: 0,
},
itemStyle: {
borderWidth: 0,
@ -60,18 +59,20 @@ onMounted(() => {
<template>
<div class="p-3">
<h2 class="text text-lg text-white mb-5 relative">用電即時分佈</h2>
<h2 class="text text-lg text-white mb-5 relative">
{{ $t("energy.elec_consumption") }}
</h2>
<div class="chart-container">
<div ref="chartDiv" class="w-full min-h-[190px] h-full"></div>
</div>
<div class="text-sm mt-3.5">
<ul class="flex flex-wrap items-center text-white">
<li class="pr-5 relative z-20">
<span class="pr-3.5">總用電 (kWh)</span>
<span class="pr-3.5"> {{ $t("energy.total_elec") }} (kWh)</span>
<span class="pr-3.5">160.05</span>
</li>
<li class="pr-5 relative z-20">
<span class="pr-3.5">綠電 (kWh)</span>
<span class="pr-3.5">{{ $t("energy.green_elec") }} (kWh)</span>
<span class="pr-3.5">39.50</span>
</li>
</ul>

View File

@ -116,11 +116,11 @@ onMounted(() => {
<div class="p-3">
<div class="flex text-white mb-5">
<div class="flex items-end text-base relative text mr-32">
即時需量
{{ $t("energy.immediate_demand") }}
<span class="text-2xl px-2.5">245.48 kw</span>
</div>
<div class="flex items-end text-base">
平均需量
{{ $t("energy.average_demand") }}
<span class="text-2xl px-2.5">230.8 kw</span>
</div>
</div>

View File

@ -95,7 +95,7 @@ onMounted(() => {
<template>
<div class="bg-slate-700 p-3">
<div class="text-white mb-3 text-base">
區間計費度數 2024 / 11 / 01 ~ 2024 / 11 / 15
{{ $t("energy.interval_bill_degree") }} 2024 / 11 / 01 ~ 2024 / 11 / 15
</div>
<div class="bar-box">
<BarChart

View File

@ -99,7 +99,7 @@ onMounted(() => {
<template>
<div class="bg-slate-800 p-3">
<div class="text-white mb-3 text-base">每月用電分析</div>
<div class="text-white mb-3 text-base">{{$t("energy.monthly_elec_consumption")}}</div>
<div class="bar-box">
<BarChart
id="electricity_bill_chart"

View File

@ -1,23 +1,33 @@
<script setup>
import { ref } from "vue";
import { ref, watch } from "vue";
import { twMerge } from "tailwind-merge";
import { useI18n } from "vue-i18n";
const { t, locale } = useI18n();
//
const dataItems = ref([
{ title: "今年電費累計(元)", data: "3,255,458" },
{ title: "區間電費(元)", data: "205,110" },
{ title: "今年碳排當量累計(公斤)", data: "455,128" },
{ title: "區間碳排當量", time: "2023-11-01~2023-11-19", data: "25,351" },
{ title: "今年用電度數(kWh)", data: "864,830" },
{ title: "區間用電度數(kWh)", time: "2023-11-01~2023-11-19", data: "50,355" },
]);
//
const getItemBackground = (index) => {
return index === 0 || index === 3 || index === 4
? "bg-slate-600"
: "bg-slate-800";
const updateDataItems = () => {
return [
{ title: t("energy.elec_bills"), data: "3,255,458" },
{ title: t("energy.interval_elec_charges"), data: "205,110" },
{ title: t("energy.year_carbon_emission"), data: "455,128" },
{
title: t("energy.interval_carbon_emission"),
time: "2023-11-01~2023-11-19",
data: "25,351",
},
{ title: t("energy.year_elec_consumption"), data: "864,830" },
{
title: t("energy.interval_elec_consumption"),
time: "2023-11-01~2023-11-19",
data: "50,355",
},
];
};
const dataItems = ref(updateDataItems());
watch(locale, () => {
dataItems.value = updateDataItems();
});
</script>
<template>
@ -27,7 +37,7 @@ const getItemBackground = (index) => {
:key="index"
:class="
twMerge(
'item w-1/2 py-0 px-5 h-[85px] text-white flex justify-center flex-col',
'item w-1/2 py-0 px-3 h-[85px] text-white flex justify-center flex-col',
index == 0 || index == 3 || index == 4
? 'bg-slate-800'
: 'bg-slate-700'

View File

@ -16,7 +16,7 @@ export default defineConfig({
server: {
proxy: {
'/upload': {
target: "http://192.168.0.206:8088/upload",
target: "https://ibms-cvilux.production.mjmtech.com.tw",
changeOrigin: true,
secure: false,
},