框架UI修改

This commit is contained in:
huliang 2025-05-19 12:06:36 +08:00
parent 48dd8d62bb
commit 704af2eb18
14 changed files with 257 additions and 227 deletions

View File

@ -1,3 +1,4 @@
{ {
"systemName": "關渡醫院中央監控" "systemName": "關渡醫院中央監控",
"is3D": true
} }

View File

@ -8,7 +8,7 @@ import useNiagaraDataStore from "@/stores/useNiagaraDataStore";
import useNavDataStore from "@/stores/useNavDataStore"; import useNavDataStore from "@/stores/useNavDataStore";
const showSidebar = ref(false); const showSidebar = ref(false);
const systemName = ref(""); const is3D = ref(false);
const userStore = useUserStore(); const userStore = useUserStore();
const niagaraStore = useNiagaraDataStore(); const niagaraStore = useNiagaraDataStore();
const navStore = useNavDataStore(); const navStore = useNavDataStore();
@ -20,25 +20,20 @@ const toggleSidebar = () => {
onMounted(async () => { onMounted(async () => {
const json = await fetch("./config.json"); const json = await fetch("./config.json");
const res = await json.json(); const res = await json.json();
systemName.value = res.systemName; is3D.value = res.is3D;
await userStore.loadUserInfo(); await userStore.loadUserInfo();
await niagaraStore.getSystemData(); await niagaraStore.getSystemData();
await navStore.getNavData(); await navStore.getNavData();
}); });
provide("app_config", { is3D });
</script> </script>
<template> <template>
<a-layout class="w-full" style="min-height: 100vh"> <a-layout class="w-full" style="min-height: 100vh">
<LeftSidebar <LeftSidebar :showSidebar="showSidebar" :toggleSidebar="toggleSidebar" />
:showSidebar="showSidebar" <Navbar :open="toggleSidebar" :userName="userStore.userName" />
:toggleSidebar="toggleSidebar"
/>
<Navbar
:systemName="systemName"
:open="toggleSidebar"
:userName="userStore.userName"
/>
<a-layout-content <a-layout-content
class="overflow-x-hidden" class="overflow-x-hidden"
:style="{ :style="{

View File

@ -1,14 +1,21 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref, inject } from "vue";
import Forge from "@/components/forge/Forge.vue"; import Forge from "@/components/forge/Forge.vue";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL; const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const type = ref("3d"); const type = ref("2d");
const { is3D } = inject("app_config");
</script> </script>
<template> <template>
<a-card class="card"> <a-card
<div class="w-full relative"> class="card h-full"
:bodyStyle="{
height: '100%',
}"
>
<div :class="twMerge('w-full relative', is3D ? '' : 'h-full')">
<img <img
alt="build" alt="build"
:src="`${FILE_BASEURL}/file/UI_images/build/2D/build.jpg`" :src="`${FILE_BASEURL}/file/UI_images/build/2D/build.jpg`"
@ -18,7 +25,7 @@ const type = ref("3d");
type == '2d' ? 'opacity-100 z-10' : 'opacity-0 z-0' type == '2d' ? 'opacity-100 z-10' : 'opacity-0 z-0'
) )
" "
style="width: 400px; height: 400px; vertical-align: middle" style="height: 100%; vertical-align: middle"
/> />
<Forge <Forge
:class=" :class="
@ -29,32 +36,18 @@ const type = ref("3d");
" "
/> />
</div> </div>
<div class="flex items-center justify-between mt-2"> <div class="mt-2" v-if="is3D">
<div> <div class="flex items-center justify-between">
<h5>Building</h5> <h5>智慧建築</h5>
<p class="text-gray-400">
掌握建築用電系統健康狀態打造智慧節能醫院
</p>
</div>
<a-radio-group v-model:value="type"> <a-radio-group v-model:value="type">
<a-radio-button value="2d">2D</a-radio-button> <a-radio-button value="2d">2D</a-radio-button>
<a-radio-button value="3d">3D</a-radio-button> <a-radio-button value="3d">3D</a-radio-button>
</a-radio-group> </a-radio-group>
</div> </div>
<!-- <a-row> <p class="intro text-gray-400">
<a-col :span="6"> 掌握建築用電系統健康狀態打造智慧節能醫院
<a-statistic title="用戶數" :value="3.6" suffix="萬" /> </p>
</a-col> </div>
<a-col :span="6">
<a-statistic title="智慧電錶" :value="82" suffix="個" />
</a-col>
<a-col :span="6">
<a-statistic title="電費支出" :value="-7.2" suffix="萬" />
</a-col>
<a-col :span="6">
<a-statistic title="警示次數" :value="15" suffix="次" />
</a-col>
</a-row> -->
</a-card> </a-card>
</template> </template>
@ -66,7 +59,11 @@ const type = ref("3d");
h5 { h5 {
margin: 0; margin: 0;
font-weight: 700; font-weight: 700;
font-size: 18px; font-size: 33px;
color: #141414; color: #141414;
} }
.intro {
font-size: 1.125rem;
}
</style> </style>

View File

@ -93,9 +93,9 @@ const generateCylinderChartOption = (data) => {
x2: 1, x2: 1,
y2: 0, y2: 0,
colorStops: [ colorStops: [
{ offset: 0, color: "#1890ff" }, // { offset: 0, color: "#69B0CF" }, //
{ offset: 0.5, color: "#acd7e4" }, // { offset: 0.5, color: "#acd7e4" }, //
{ offset: 1, color: "#1890ff" }, // { offset: 1, color: "#69B0CF" }, //
], ],
}; };
const color2 = { const color2 = {
@ -106,9 +106,9 @@ const generateCylinderChartOption = (data) => {
x2: 1, x2: 1,
y2: 0, y2: 0,
colorStops: [ colorStops: [
{ offset: 0, color: "#91cc75" }, // { offset: 0, color: "#E7F5A7" }, //
{ offset: 0.5, color: "#d2f0c2" }, // { offset: 0.5, color: "#ebffe0" }, //
{ offset: 1, color: "#91cc75" }, // { offset: 1, color: "#E7F5A7" }, //
], ],
}; };
@ -190,9 +190,9 @@ const generateCylinderChartOption = (data) => {
symbolPosition: "end", symbolPosition: "end",
data: data.values[1].value, data: data.values[1].value,
itemStyle: { itemStyle: {
color: "#d2f0c2", color: "#ebffe0",
borderWidth: 1, borderWidth: 1,
borderColor: "#91cc75", borderColor: "#E7F5A7",
borderType: "solid", borderType: "solid",
}, },
z: 12, z: 12,
@ -207,7 +207,7 @@ const generateCylinderChartOption = (data) => {
data: data.values[0].value, data: data.values[0].value,
z: 12, z: 12,
itemStyle: { itemStyle: {
color: "#1890ff", color: "#69B0CF",
}, },
}, },
{ {
@ -218,7 +218,7 @@ const generateCylinderChartOption = (data) => {
symbolPosition: "start", symbolPosition: "start",
data: data.values[1].value, data: data.values[1].value,
itemStyle: { itemStyle: {
color: "#91cc75", color: "#E7F5A7",
}, },
z: 12, z: 12,
}, },

View File

@ -1,5 +1,6 @@
<script setup> <script setup>
import { defineProps } from "vue"; import { defineProps } from "vue";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const props = defineProps({ const props = defineProps({
elecData: { elecData: {
type: Object, type: Object,
@ -20,7 +21,7 @@ const props = defineProps({
</a-col> </a-col>
<a-col :span="6" class="pl-0"> <a-col :span="6" class="pl-0">
<div class="icon-box"> <div class="icon-box">
<font-awesome-icon :icon="['fas', item.icon]" size="2x"/> <img :src="`${FILE_BASEURL}/file/UI_images/stat/${item.icon}.svg`" alt="icon">
</div> </div>
</a-col> </a-col>
</a-row> </a-row>
@ -52,11 +53,5 @@ const props = defineProps({
.icon-box { .icon-box {
width: 48px; width: 48px;
height: 48px; height: 48px;
text-align: center;
background: #1890ff;
color: #fff;
border-radius: 0.5rem;
margin-left: auto;
line-height: 55px;
} }
</style> </style>

View File

@ -47,8 +47,9 @@ const handleClick = (ord) => {
router.push({ router.push({
name: "baja", name: "baja",
query: { query: {
pagename: 'system', pagename: "system",
ord: encodeURIComponent(ord) }, ord: encodeURIComponent(ord),
},
}); });
} }
}; };
@ -65,7 +66,7 @@ const handleClick = (ord) => {
<a-col :span="6" v-for="item in flattenedItems" :key="item.key"> <a-col :span="6" v-for="item in flattenedItems" :key="item.key">
<a-card <a-card
@click="handleClick(item.ord)" @click="handleClick(item.ord)"
class="shadow" class="shadow inner-card"
:bodyStyle="{ :bodyStyle="{
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
@ -79,7 +80,7 @@ const handleClick = (ord) => {
alt="Icon" alt="Icon"
style="width: 30px; height: 30px; vertical-align: middle" style="width: 30px; height: 30px; vertical-align: middle"
/> />
<span class="text-lg">{{ item.label }}</span> <span class="text-lg text-white">{{ item.label }}</span>
</a-card> </a-card>
</a-col> </a-col>
</a-row> </a-row>
@ -92,6 +93,9 @@ const handleClick = (ord) => {
.card { .card {
box-shadow: 0 20px 27px rgb(0 0 0 / 5%); box-shadow: 0 20px 27px rgb(0 0 0 / 5%);
} }
.inner-card {
background-color: #69b0cf;
}
h5 { h5 {
margin: 0; margin: 0;
font-weight: 700; font-weight: 700;

View File

@ -18,12 +18,11 @@ const preOpenKeys = ref([]); // 用於儲存之前展開的 submenu
const filteredItems = computed(() => { const filteredItems = computed(() => {
if (navStore.menuList && navStore.menuList.length > 0) { if (navStore.menuList && navStore.menuList.length > 0) {
if(navStore.menuList[0].children.length > 1){ if (navStore.menuList[0].children.length > 1) {
return navStore.menuList[0].children; return navStore.menuList[0].children;
}else{ } else {
return navStore.menuList[0].children[0].children; return navStore.menuList[0].children[0].children;
} }
} }
return []; return [];
}); });
@ -32,8 +31,7 @@ const handleClick = (ord) => {
if (ord) { if (ord) {
router.push({ router.push({
name: "baja", name: "baja",
query: { pagename: 'system', query: { pagename: "system", ord: encodeURIComponent(ord) },
ord: encodeURIComponent(ord) },
}); });
} }
}; };
@ -55,9 +53,12 @@ watch(
:closable="false" :closable="false"
placement="left" placement="left"
width="300" width="300"
bodyStyle="padding: 0" :bodyStyle="{
padding: 0,
backgroundColor: '#69b0cf',
}"
> >
<a-menu mode="inline" theme="light"> <a-menu mode="inline" theme="light" class="sidebarMenu">
<template v-for="(item, index) in filteredItems" :key="index"> <template v-for="(item, index) in filteredItems" :key="index">
<a-menu-item <a-menu-item
v-if="!item.children" v-if="!item.children"
@ -94,3 +95,20 @@ watch(
</a-menu> </a-menu>
</a-drawer> </a-drawer>
</template> </template>
<style>
.sidebarMenu {
background-color: transparent;
color: #fff;
}
.sidebarMenu .ant-menu-submenu-selected > .ant-menu-submenu-title {
color: #fff;
}
.sidebarMenu .ant-menu-item:hover {
background-color: #e7f5a7 !important;
}
.sidebarMenu .ant-menu-item-selected {
background-color: #e7f5a7 !important;
color: #333 !important;
}
</style>

View File

@ -3,7 +3,7 @@ import { ref, computed, onBeforeUnmount, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import useNiagaraDataStore from "@/stores/useNiagaraDataStore"; import useNiagaraDataStore from "@/stores/useNiagaraDataStore";
import useAlarmDataStore from "@/stores/useAlarmDataStore"; import useAlarmDataStore from "@/stores/useAlarmDataStore";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const router = useRouter(); const router = useRouter();
const niagaraStore = useNiagaraDataStore(); const niagaraStore = useNiagaraDataStore();
const alarmDataStore = useAlarmDataStore(); const alarmDataStore = useAlarmDataStore();
@ -56,7 +56,7 @@ onBeforeUnmount(() => {
</template> </template>
<a-badge :count="totalAlarmCount" :overflow-count="999" class="!mt-3"> <a-badge :count="totalAlarmCount" :overflow-count="999" class="!mt-3">
<a class="flex flex-col items-center"> <a class="flex flex-col items-center">
<font-awesome-icon :icon="['fas', 'bell']" size="2x" /> <img :src="`${FILE_BASEURL}/file/UI_images/icon/notify.svg`" alt="notify_icon" class="icon" />
<span class="text-sm">告警</span> <span class="text-sm">告警</span>
</a> </a>
</a-badge> </a-badge>

View File

@ -1,138 +1,22 @@
<script setup> <script setup>
import { ref, onMounted, onUnmounted } from "vue"; import { nextTick, onMounted, onUnmounted } from "vue";
import { import useWeatherDataStore from "@/stores/useWeatherDataStore";
imagesWeatherDay,
imagesWeatherNight,
orderWeather,
} from "@/constants";
const weatherStateText = ref("N/A");
const weatherStateImage = ref(null);
const actualWeather = ref("Clear");
const temperature = ref("N/A");
const humidity = ref("N/A");
const actualNighttime = ref(false);
const dateTime = ref("N/A");
const weatherStore = useWeatherDataStore();
let intervalId = null; let intervalId = null;
let subscriber = null; // subscriber
// onMounted(async () => {
const initializeData = () => { console.log('window.require',window.require);
if (window.require && window.requirejs) {
window.requirejs(["baja!"], (baja) => {
subscriber = new baja.Subscriber(); // subscriber
subscriber.attach("changed", (prop) => {
console.log(
"weather",
prop,
prop.$getDisplayName(),
prop.$getValue().getValueDisplay()
);
// slotName await weatherStore.subscribeToWeather();
if (prop.$slotName === "temp") { //
temperature.value = prop.$getValue().getValueDisplay(); weatherStore.updateTime();
} else if (prop.$slotName === "humidity") { intervalId = setInterval(weatherStore.updateTime, 1000);
humidity.value = prop.$getValue().getValueDisplay();
} else if (prop.$slotName === "state") {
actualWeather.value = prop.$getValue().getValueDisplay();
loadWeather(actualWeather.value); //
} else if (prop.$slotName === "sunDown") {
actualNighttime.value = !prop.$getValue().getValueDisplay();
loadWeather(actualWeather.value); //
}
});
// Niagara
baja.Ord.make(
"station:|slot:/Services/WeatherService/WeatherService/WeatherService/current"
)
.get({ subscriber })
.then((result) => {
console.log("Successfuly subscribed to weather data", result);
})
.catch((err) => {
console.error(`訂閱 weather 失敗: ${err.message}`);
subscriber.detach("changed"); //
});
});
} else {
console.error("未能載入 Baja 環境,請確認依賴已正確加載。");
}
};
//
const loadWeather = (actualWeather) => {
console.log(
"actualWeather",
actualWeather.replace(/\s/g, ""),
actualNighttime.value
);
let weatherStateTextTemp = "Unknown";
let weatherStateImageTemp = null;
// actualWeather orderWeather
const actualWeatherIndex = orderWeather.indexOf(
actualWeather.replace(/\s/g, "")
);
if (actualWeatherIndex === -1) {
// weather orderWeather
console.error("天氣狀態不在 orderWeather 陣列中!實際值:" + actualWeather);
weatherStateTextTemp = "Unknown";
weatherStateImageTemp = imagesWeatherDay[weatherStateTextTemp];
} else if (actualWeather === "none") {
console.warn("未設定天氣狀態或點不存在");
weatherStateTextTemp = "Unknown";
weatherStateImageTemp = imagesWeatherDay[weatherStateTextTemp];
} else {
if (actualNighttime.value) {
console.log("Nighttime activ");
weatherStateTextTemp = orderWeather[actualWeatherIndex];
weatherStateImageTemp = imagesWeatherNight[weatherStateTextTemp];
} else {
console.log("Daytime activ");
weatherStateTextTemp = orderWeather[actualWeatherIndex];
weatherStateImageTemp = imagesWeatherDay[weatherStateTextTemp];
}
}
weatherStateImage.value = weatherStateImageTemp;
weatherStateText.value = weatherStateTextTemp; //
};
//
const updateTime = () => {
const date = new Date();
if (window.require && window.requirejs) {
window.requirejs(["baja!"], (baja) => {
const bAbsTime = baja.AbsTime.make({ jsDate: date });
bAbsTime
.toDateTimeString()
.then((dateTimeStr) => {
dateTime.value = dateTimeStr;
})
.catch((error) => {
console.error("轉換時間字串失敗:", error);
});
});
}
};
onMounted(() => {
updateTime(); //
intervalId = setInterval(updateTime, 1000);
setTimeout(() => {
initializeData();
}, 1000);
}); });
onUnmounted(() => { onUnmounted(() => {
clearInterval(intervalId); clearInterval(intervalId);
if (subscriber) { weatherStore.clearAllSubscriber();
subscriber.detachAll(); //
}
}); });
</script> </script>
@ -140,15 +24,15 @@ onUnmounted(() => {
<div class="leading-none pt-2"> <div class="leading-none pt-2">
<p class="flex items-center"> <p class="flex items-center">
<img <img
v-if="weatherStateImage" v-if="weatherStore.weatherStateImage"
:src="weatherStateImage" :src="weatherStore.weatherStateImage"
alt="Weather Icon" alt="Weather Icon"
style="width: 20px; height: 20px; vertical-align: middle" style="width: 20px; height: 20px; vertical-align: middle"
/> />
- {{ weatherStateText }} - {{ weatherStore.weatherStateText }}
</p> </p>
<p>{{ temperature }} | {{ humidity }}</p> <p>{{ weatherStore.temperature }} | {{ weatherStore.humidity }}</p>
<p>{{ dateTime }}</p> <p>{{ weatherStore.dateTime }}</p>
</div> </div>
</template> </template>

View File

@ -6,7 +6,7 @@ import NavWeather from "./NavWeather.vue";
import NavAlarm from "./NavAlarm.vue"; import NavAlarm from "./NavAlarm.vue";
import useNiagaraDataStore from "@/stores/useNiagaraDataStore"; import useNiagaraDataStore from "@/stores/useNiagaraDataStore";
import useNavDataStore from "@/stores/useNavDataStore"; import useNavDataStore from "@/stores/useNavDataStore";
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const niagaraStore = useNiagaraDataStore(); const niagaraStore = useNiagaraDataStore();
@ -163,7 +163,7 @@ watch(
</a-menu> </a-menu>
</template> </template>
<a class="flex flex-col items-center pt-3"> <a class="flex flex-col items-center pt-3">
<font-awesome-icon :icon="['fas', 'user']" size="2x" /> <img :src="`${FILE_BASEURL}/file/UI_images/icon/user.svg`" alt="user_icon" class="icon" />
<span class="text-sm">{{ props.userName }}</span> <span class="text-sm">{{ props.userName }}</span>
</a> </a>
</a-dropdown> </a-dropdown>
@ -217,11 +217,13 @@ watch(
width: 30px; width: 30px;
height: 30px; height: 30px;
vertical-align: middle; vertical-align: middle;
margin-left: 20px;
} }
.icon { .icon {
width: 30px; width: 30px;
height: 30px; height: 30px;
vertical-align: middle; vertical-align: middle;
fill: #69B0CF;
} }
</style> </style>

View File

@ -56,7 +56,7 @@ const useElecStore = defineStore("elecData", () => {
eleclist.push({ eleclist.push({
slotPath: record.get("slotPath"), slotPath: record.get("slotPath"),
displayName: record.get("parent$2edisplayName"), displayName: record.get("parent$2edisplayName"),
id: record.get("NumericInterval$2ehistoryConfig$2eid").$cEncStr, id: record.get("NumericInterval$2ehistoryConfig$2eid"),
out: record.get("out")?.get("value") ?? null, out: record.get("out")?.get("value") ?? null,
}); });
}, },
@ -77,15 +77,15 @@ const useElecStore = defineStore("elecData", () => {
const gettimeToHistory = (item) => { const gettimeToHistory = (item) => {
const id = item.id; const id = item.id;
const startTime = dayjs() const startTime = dayjs("2025-05-08T16:30:00.000+08:00")
.subtract(13, "day") .subtract(13, "day")
.startOf("day") .startOf("day")
.format("YYYY-MM-DDTHH:mm:ss.000+08:00"); .format("YYYY-MM-DDTHH:mm:ss.000+08:00");
const endTime = dayjs() const endTime = dayjs("2025-05-08T16:30:00.000+08:00")
.endOf("day") .endOf("day")
.format("YYYY-MM-DDTHH:mm:ss.000+08:00"); .format("YYYY-MM-DDTHH:mm:ss.000+08:00");
const ordString = `local:|foxs:4918|history:${id}?period=timerange;;start=${startTime};end=${endTime}|bql:history:HistoryRollup.rollup(baja:RelTime '3600000')`; //每小时一个rollup const ordString = `local:|foxs:4918|history:${id}?period=timerange;start=${startTime};end=${endTime}|bql:history:HistoryRollup.rollup(baja:RelTime '3600000')`; //每小时一个rollup
console.log(ordString); console.log(ordString);
// @ts-ignore // @ts-ignore
window.require && window.require &&
@ -105,6 +105,7 @@ const useElecStore = defineStore("elecData", () => {
const timestamp = record.get("timestamp").$cEncStr; const timestamp = record.get("timestamp").$cEncStr;
if ( if (
currentValue !== null && currentValue !== null &&
!isNaN(currentValue) &&
currentValue !== 0 && currentValue !== 0 &&
timestamp !== null timestamp !== null
) { ) {
@ -129,8 +130,8 @@ const useElecStore = defineStore("elecData", () => {
// 提取今天和昨天的数据 // 提取今天和昨天的数据
for (const [timestamp, value] of dataMap) { for (const [timestamp, value] of dataMap) {
const date = dayjs(timestamp).format("YYYY-MM-DD"); const date = dayjs(timestamp).format("YYYY-MM-DD");
const today = dayjs().format("YYYY-MM-DD"); const today = dayjs("2025-05-08T16:30:00.000+08:00").format("YYYY-MM-DD");
const yesterday = dayjs().subtract(1, "day").format("YYYY-MM-DD"); const yesterday = dayjs("2025-05-08T16:30:00.000+08:00").subtract(1, "day").format("YYYY-MM-DD");
if (date === today) { if (date === today) {
todayelecdata.value.set(timestamp, value); todayelecdata.value.set(timestamp, value);

View File

@ -0,0 +1,128 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import {
imagesWeatherDay,
imagesWeatherNight,
orderWeather,
} from "@/constants";
const useWeatherDataStore = defineStore("weatherData", () => {
const weatherStateText = ref("N/A");
const weatherStateImage = ref(null);
const actualWeather = ref("Clear");
const temperature = ref("N/A");
const humidity = ref("N/A");
const actualNighttime = ref(false);
const dateTime = ref("N/A");
const subscribers = ref([]);
const subscribeToWeather = () => {
window.require &&
window.requirejs(["baja!"], (baja) => {
const subscriber = new baja.Subscriber(); // 初始化 subscriber
subscriber.attach("changed", (prop) => {
// 根據 slotName 判斷資料類型
if (prop.$slotName === "temp") {
temperature.value = prop.$getValue().getValueDisplay();
} else if (prop.$slotName === "humidity") {
humidity.value = prop.$getValue().getValueDisplay();
} else if (prop.$slotName === "state") {
actualWeather.value = prop.$getValue().getValueDisplay();
loadWeather(actualWeather.value); // 載入天氣資料
} else if (prop.$slotName === "sunDown") {
actualNighttime.value = !prop.$getValue().getValueDisplay();
loadWeather(actualWeather.value); // 重新載入天氣資料
}
});
// 訂閱 Niagara 資料
baja.Ord.make(
"station:|slot:/Services/WeatherService/WeatherService/WeatherService/current"
)
.get({ subscriber })
.then((result) => {
console.log("Successfuly subscribed to weather data", result);
})
.catch((err) => {
console.error(`訂閱 weather 失敗: ${err.message}`);
subscriber.detach("changed"); // 發生錯誤時取消訂閱
});
subscribers.value.push(subscriber);
});
};
// 載入天氣資料函數
const loadWeather = (actualWeather) => {
let weatherStateTextTemp = "Unknown";
let weatherStateImageTemp = null;
// 找到 actualWeather 在 orderWeather 中的索引
const actualWeatherIndex = orderWeather.indexOf(
actualWeather.replace(/\s/g, "")
);
if (actualWeatherIndex === -1) {
// 如果找不到,表示 weather 狀態不在 orderWeather 中
console.error(
"天氣狀態不在 orderWeather 陣列中!實際值:" + actualWeather
);
weatherStateTextTemp = "Unknown";
weatherStateImageTemp = imagesWeatherDay[weatherStateTextTemp];
} else if (actualWeather === "none") {
console.warn("未設定天氣狀態或點不存在");
weatherStateTextTemp = "Unknown";
weatherStateImageTemp = imagesWeatherDay[weatherStateTextTemp];
} else {
if (actualNighttime.value) {
console.log("Nighttime activ");
weatherStateTextTemp = orderWeather[actualWeatherIndex];
weatherStateImageTemp = imagesWeatherNight[weatherStateTextTemp];
} else {
console.log("Daytime activ");
weatherStateTextTemp = orderWeather[actualWeatherIndex];
weatherStateImageTemp = imagesWeatherDay[weatherStateTextTemp];
}
}
weatherStateImage.value = weatherStateImageTemp;
weatherStateText.value = weatherStateTextTemp; // 更新天氣狀態
};
const updateTime = () => {
const date = new Date();
window.require &&
window.requirejs(["baja!"], (baja) => {
const bAbsTime = baja.AbsTime.make({ jsDate: date });
bAbsTime
.toDateTimeString()
.then((dateTimeStr) => {
dateTime.value = dateTimeStr;
})
.catch((error) => {
console.error("轉換時間字串失敗:", error);
});
});
};
const clearAllSubscriber = () => {
subscribers.value.forEach((subscriber) => {
subscriber.detach("changed");
});
subscribers.value = [];
};
return {
weatherStateText,
weatherStateImage,
actualWeather,
temperature,
humidity,
actualNighttime,
dateTime,
subscribeToWeather,
updateTime,
clearAllSubscriber,
};
});
export default useWeatherDataStore;

View File

@ -1,4 +1,9 @@
@import "tailwindcss"; @import "tailwindcss";
:root { :root {
font-family:"Microsoft JhengHei", "Noto Sans CJK TC", STHeiti, sans-serif, serif; font-family: "Microsoft JhengHei", "Noto Sans CJK TC", STHeiti, sans-serif,
serif;
}
a {
color: #69b0cf;
} }

View File

@ -16,25 +16,25 @@ const elecStat = ref([
value: 0, value: 0,
label: "今日用電量", label: "今日用電量",
unit: "kWH", unit: "kWH",
icon: "leaf", icon: "elec",
}, },
{ {
value: 0, value: 0,
label: "昨日用電量", label: "昨日用電量",
unit: "kWH", unit: "kWH",
icon: "leaf", icon: "elec",
}, },
{ {
value: 0, value: 0,
label: "即時功率", label: "即時功率",
unit: "kW", unit: "kW",
icon: "bolt", icon: "power",
}, },
{ {
value: 0, value: 0,
label: "契約容量佔比", label: "契約容量佔比",
unit: "%", unit: "%",
icon: "charging-station", icon: "pie",
}, },
]); ]);
const elecDemand_P = ref(0); // const elecDemand_P = ref(0); //
@ -43,11 +43,11 @@ const yesterdayTodayData = ref({
categories: [], categories: [],
values: [ values: [
{ {
name: `${dayjs().format("YYYY-MM-DD")} 用電量`, name: `${dayjs("2025-05-08T16:30:00.000+08:00").format("YYYY-MM-DD")} 用電量`,
value: [], value: [],
}, },
{ {
name: `${dayjs().subtract(1, "day").format("YYYY-MM-DD")} 用電量`, name: `${dayjs("2025-05-08T16:30:00.000+08:00").subtract(1, "day").format("YYYY-MM-DD")} 用電量`,
value: [], value: [],
}, },
], ],
@ -68,7 +68,7 @@ const weekComparisonData = ref({
}); });
const generateWeekCategories = () => { const generateWeekCategories = () => {
const today = dayjs(); const today = dayjs("2025-05-08T16:30:00.000+08:00");
const currentDay = today.day(); const currentDay = today.day();
const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const daysOfWeek = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const dynamicCategories = []; const dynamicCategories = [];
@ -91,8 +91,8 @@ watch(
(newElecData) => { (newElecData) => {
console.log("elecStandCostSummary", newElecData); console.log("elecStandCostSummary", newElecData);
if (newElecData && newElecData.dailyResults) { if (newElecData && newElecData.dailyResults) {
const today = dayjs().format("YYYY-MM-DD"); const today = dayjs("2025-05-08T16:30:00.000+08:00").format("YYYY-MM-DD");
const yesterday = dayjs().subtract(1, "day").format("YYYY-MM-DD"); const yesterday = dayjs("2025-05-08T16:30:00.000+08:00").subtract(1, "day").format("YYYY-MM-DD");
const todayData = newElecData.dailyResults.find( const todayData = newElecData.dailyResults.find(
(item) => item.dateStr === today (item) => item.dateStr === today
@ -107,11 +107,11 @@ watch(
elecStat.value = [ elecStat.value = [
{ {
...elecStat.value[0], ...elecStat.value[0],
value: todayElecCost, value: todayElecCost.toFixed(2),
}, },
{ {
...elecStat.value[1], ...elecStat.value[1],
value: yesterdayElecCost, value: yesterdayElecCost.toFixed(2),
}, },
{ {
...elecStat.value[2], ...elecStat.value[2],
@ -151,8 +151,8 @@ watch(
([newTodayData, newYesterdayData]) => { ([newTodayData, newYesterdayData]) => {
console.log("todayyesterday", newTodayData, newYesterdayData); console.log("todayyesterday", newTodayData, newYesterdayData);
const todayDate = dayjs().format("YYYY-MM-DD"); const todayDate = dayjs("2025-05-08T16:30:00.000+08:00").format("YYYY-MM-DD");
const yesterdayDate = dayjs().subtract(1, "day").format("YYYY-MM-DD"); const yesterdayDate = dayjs("2025-05-08T16:30:00.000+08:00").subtract(1, "day").format("YYYY-MM-DD");
const categories = []; const categories = [];
const todayValues = []; const todayValues = [];