路徑修正

This commit is contained in:
huliang 2025-06-03 16:20:10 +08:00
parent 704af2eb18
commit 5555a51579
18 changed files with 147 additions and 71 deletions

2
.env
View File

@ -1 +1 @@
VITE_FILE_API_BASEURL = "https://192.168.0.206:8500" VITE_FILE_API_BASEURL = ".."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

View File

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

View File

@ -1,22 +1,19 @@
<script setup> <script setup>
import { ref, onMounted, watch } from "vue";
import useNiagaraDataStore from "@/stores/useNiagaraDataStore";
import useAlarmDataStore from "@/stores/useAlarmDataStore"; import useAlarmDataStore from "@/stores/useAlarmDataStore";
const niagaraStore = useNiagaraDataStore();
const alarmDataStore = useAlarmDataStore(); const alarmDataStore = useAlarmDataStore();
</script> </script>
<template> <template>
<a-card class="card"> <a-card class="card">
<h5>異常告警</h5> <h5 class="mb-4">異常告警</h5>
<table className="table w-full"> <table className="table w-full text-center">
<thead> <thead>
<tr> <tr>
<th>異常類別</th> <th>異常類別</th>
<th>發報中</th> <th>發報中</th>
<th>未確認</th> <th>未確認</th>
<th></th> <th>操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -39,10 +36,9 @@ const alarmDataStore = useAlarmDataStore();
<router-link <router-link
:to="{ :to="{
name: 'baja', name: 'baja',
query: { pagename: 'alert', query: { pagename: 'alert', ord: encodeURIComponent(item.Ord) },
ord: encodeURIComponent(item.Ord) },
}" }"
class="flex items-center justify-between gap-8" class=""
>查看</router-link >查看</router-link
> >
</td> </td>
@ -56,22 +52,22 @@ const alarmDataStore = useAlarmDataStore();
box-shadow: 0 20px 27px rgb(0 0 0 / 5%); box-shadow: 0 20px 27px rgb(0 0 0 / 5%);
} }
h5 { h5 {
margin: 0;
font-weight: 700; font-weight: 700;
font-size: 33px; font-size: 30px;
color: #141414; color: #141414;
} }
.table th { .table th {
text-align: left; border: 1px solid #898989;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); font-size: 1.1rem;
font-size: 1.125rem;
font-weight: 600; font-weight: 600;
padding: 8px 0; padding: 8px 0;
color: #8c8c8c; color: #8c8c8c;
background-color: #e7f5a7;
} }
.table td { .table td {
font-size: 1.125rem; border: 1px solid #898989;
font-size: 1.1rem;
padding: 8px 0px; padding: 8px 0px;
white-space: nowrap; white-space: nowrap;
} }

View File

@ -18,7 +18,7 @@ const { is3D } = inject("app_config");
<div :class="twMerge('w-full relative', is3D ? '' : 'h-full')"> <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}/UI_images/build/2D/build.jpg`"
:class=" :class="
twMerge( twMerge(
'absolute left-1/2 translate-x-[-50%] rounded shadow-lg transition-opacity duration-300', 'absolute left-1/2 translate-x-[-50%] rounded shadow-lg transition-opacity duration-300',
@ -59,7 +59,7 @@ const { is3D } = inject("app_config");
h5 { h5 {
margin: 0; margin: 0;
font-weight: 700; font-weight: 700;
font-size: 33px; font-size: 30px;
color: #141414; color: #141414;
} }

View File

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

View File

@ -21,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">
<img :src="`${FILE_BASEURL}/file/UI_images/stat/${item.icon}.svg`" alt="icon"> <img :src="`${FILE_BASEURL}/UI_images/stat/${item.icon}.svg`" alt="icon">
</div> </div>
</a-col> </a-col>
</a-row> </a-row>

View File

@ -93,13 +93,19 @@ 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 { .inner-card {
background-color: #69b0cf; background-color: #69b0cf;
} }
.inner-card:hover {
opacity: 0.75;
}
h5 { h5 {
margin: 0; margin: 0;
font-weight: 700; font-weight: 700;
font-size: 33px; font-size: 30px;
color: #141414; color: #141414;
} }
</style> </style>

View File

@ -52,7 +52,7 @@ const loadModel = (filePath) => {
onMounted(async () => { onMounted(async () => {
console.log("Forge 加載"); console.log("Forge 加載");
await initViewer(forgeDom.value); await initViewer(forgeDom.value);
const filePath = `${FILE_BASEURL}/file/UI_images/build/3D/0.svf`; const filePath = `${FILE_BASEURL}/UI_images/build/3D/0.svf`;
loadModel(filePath); loadModel(filePath);
}); });

View File

@ -65,9 +65,24 @@ watch(
:key="item.key" :key="item.key"
@click="handleClick(item.ord)" @click="handleClick(item.ord)"
> >
{{ item.label }} <img
v-if="item.icon"
:src="item.icon"
alt="Icon"
style="width: 20px; height: 20px; vertical-align: middle"
/>
<span>{{ item.label }}</span>
</a-menu-item> </a-menu-item>
<a-sub-menu v-else :title="item.label" :key="`submenu-${item.key}`"> <a-sub-menu v-else :key="`submenu-${item.key}`">
<template #title>
<img
v-if="item.icon"
:src="item.icon"
alt="Icon"
style="width: 20px; height: 20px; vertical-align: middle"
/>
<span>{{ item.label }}</span>
</template>
<template v-for="child in item.children" :key="child.key"> <template v-for="child in item.children" :key="child.key">
<a-menu-item <a-menu-item
v-if="!child.children" v-if="!child.children"
@ -101,14 +116,34 @@ watch(
background-color: transparent; background-color: transparent;
color: #fff; color: #fff;
} }
.sidebarMenu .ant-menu-submenu-title > .ant-menu-title-content,
.sidebarMenu .ant-menu-item > .ant-menu-title-content {
display: flex;
align-items: center;
gap: 4px;
}
.sidebarMenu .ant-menu-submenu-selected > .ant-menu-submenu-title { .sidebarMenu .ant-menu-submenu-selected > .ant-menu-submenu-title {
color: #fff; color: #fff;
} }
.sidebarMenu .ant-menu-submenu-title:hover,
.sidebarMenu .ant-menu-item:hover { .sidebarMenu .ant-menu-item:hover {
background-color: #e7f5a7 !important; background-color: #e7f5a7 !important;
} }
.sidebarMenu .ant-menu-submenu-title:hover img,
.sidebarMenu .ant-menu-item:hover img {
filter: brightness(0);
}
.sidebarMenu .ant-menu-item-selected { .sidebarMenu .ant-menu-item-selected {
background-color: #e7f5a7 !important; background-color: #e7f5a7 !important;
color: #333 !important; color: #333 !important;
} }
.sidebarMenu .ant-menu-item-selected img {
filter: brightness(0);
}
</style> </style>

View File

@ -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">
<img :src="`${FILE_BASEURL}/file/UI_images/icon/notify.svg`" alt="notify_icon" class="icon" /> <img :src="`${FILE_BASEURL}/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,21 +1,24 @@
<script setup> <script setup>
import { nextTick, onMounted, onUnmounted } from "vue"; import { onMounted, onUnmounted, watch } from "vue";
import useNiagaraDataStore from "@/stores/useNiagaraDataStore";
import useWeatherDataStore from "@/stores/useWeatherDataStore"; import useWeatherDataStore from "@/stores/useWeatherDataStore";
const niagaraStore = useNiagaraDataStore();
const weatherStore = useWeatherDataStore(); const weatherStore = useWeatherDataStore();
let intervalId = null;
onMounted(async () => { watch(
console.log('window.require',window.require); () => niagaraStore.weatherList,
(newValue, oldValue) => {
await weatherStore.subscribeToWeather(); if (newValue) {
// weatherStore.subscribeToWeather();
weatherStore.updateTime(); weatherStore.updateTime();
intervalId = setInterval(weatherStore.updateTime, 1000); weatherStore.startUpdateTimeInterval();
}); }
},
{ immediate: true }
);
onUnmounted(() => { onUnmounted(() => {
clearInterval(intervalId);
weatherStore.clearAllSubscriber(); weatherStore.clearAllSubscriber();
}); });
</script> </script>

View File

@ -72,7 +72,7 @@ const userList = computed(() => niagaraStore.userList?.children || []);
watch( watch(
() => route.query.pagename, () => route.query.pagename,
(newPagename) => { (newPagename) => {
activePageName.value = newPagename || "home" ; // activePageName.value = newPagename || "home"; //
}, },
{ {
immediate: true, immediate: true,
@ -89,7 +89,7 @@ watch(
}}</a> }}</a>
<!-- <NavBuild /> --> <!-- <NavBuild /> -->
</div> </div>
<ul class="nav-menu flex gap-10"> <ul class="nav-menu flex gap-5">
<li :class="{ 'link-active': activePageName === 'home' }"> <li :class="{ 'link-active': activePageName === 'home' }">
<router-link <router-link
:to=" :to="
@ -133,7 +133,7 @@ watch(
</router-link> </router-link>
</li> </li>
</ul> </ul>
<ul class="nav-menu flex gap-10"> <ul class="nav-menu flex gap-2">
<li> <li>
<NavWeather /> <NavWeather />
</li> </li>
@ -163,7 +163,11 @@ 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">
<img :src="`${FILE_BASEURL}/file/UI_images/icon/user.svg`" alt="user_icon" class="icon" /> <img
:src="`${FILE_BASEURL}/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>
@ -173,17 +177,31 @@ watch(
</template> </template>
<style lang="css" scoped> <style lang="css" scoped>
.nav-menu li {
padding: 5px 10px;
}
.nav-menu li a { .nav-menu li a {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
} }
.nav-menu li.link-active .icon { .nav-menu li a:hover {
filter: brightness(1.2); opacity: 0.75;
} }
.nav-menu li.link-active {
background: #e7f5a7;
border-radius: 5px;
}
.nav-menu li.link-active .icon {
filter: brightness(0);
}
.nav-menu li.link-active span { .nav-menu li.link-active span {
color: #43daff; color: #000000;
} }
.header { .header {
@ -224,6 +242,6 @@ watch(
width: 30px; width: 30px;
height: 30px; height: 30px;
vertical-align: middle; vertical-align: middle;
fill: #69B0CF; fill: #69b0cf;
} }
</style> </style>

View File

@ -13,7 +13,7 @@ const useElecDemandStore = defineStore("elecDemand", () => {
window.requirejs(["baja!"], (baja) => { window.requirejs(["baja!"], (baja) => {
let eleclist = []; let eleclist = [];
baja.Ord.make( baja.Ord.make(
`local:|foxs:4918|station:|neql:EMS:kw|bql:select slotPath,parent.displayName,name,out` `local:|foxs:|station:|neql:EMS:kw|bql:select slotPath,parent.displayName,name,out`
).get({ ).get({
cursor: { cursor: {
before: () => {}, before: () => {},
@ -40,7 +40,7 @@ const useElecDemandStore = defineStore("elecDemand", () => {
const subscribeToHistory = (item, index) => { const subscribeToHistory = (item, index) => {
const slotPath = item.slotPath; const slotPath = item.slotPath;
const ordString = `local:|foxs:4918|station:|${slotPath}`; const ordString = `local:|foxs:|station:|${slotPath}`;
// @ts-ignore // @ts-ignore
window.require && window.require &&

View File

@ -18,7 +18,7 @@ const useElecStore = defineStore("elecData", () => {
console.log("進入 bajaSubscriber 準備執行用電價 BQL 訂閱"); console.log("進入 bajaSubscriber 準備執行用電價 BQL 訂閱");
// 定義BQL 查詢 // 定義BQL 查詢
const price_kwhBql = `local:|foxs:4918|station:|neql:EMS:parameter|bql:select slotPath,parent.displayName,displayName,NumericInterval.historyConfig.id,out`; const price_kwhBql = `local:|foxs:|station:|neql:EMS:parameter|bql:select slotPath,parent.displayName,displayName,NumericInterval.historyConfig.id,out`;
// 執行查詢 // 執行查詢
let pricelist = []; let pricelist = [];
@ -45,7 +45,7 @@ const useElecStore = defineStore("elecData", () => {
console.log("進入 bajaSubscriber 準備執行用電度數 BQL 訂閱"); console.log("進入 bajaSubscriber 準備執行用電度數 BQL 訂閱");
// 定義BQL 查詢 // 定義BQL 查詢
const Total_kwhBql = `local:|foxs:4918|station:|neql:EMS:Total_kwh|bql:select slotPath,parent.displayName,displayName,NumericInterval.historyConfig.id,out`; const Total_kwhBql = `local:|foxs:|station:|neql:EMS:Total_kwh|bql:select slotPath,parent.displayName,displayName,NumericInterval.historyConfig.id,out`;
// 執行各電表的 BQL 查詢 // 執行各電表的 BQL 查詢
let eleclist = []; let eleclist = [];
@ -85,7 +85,7 @@ const useElecStore = defineStore("elecData", () => {
.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:|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 &&

View File

@ -5,6 +5,7 @@ import {
imagesWeatherNight, imagesWeatherNight,
orderWeather, orderWeather,
} from "@/constants"; } from "@/constants";
import dayjs from "dayjs";
const useWeatherDataStore = defineStore("weatherData", () => { const useWeatherDataStore = defineStore("weatherData", () => {
const weatherStateText = ref("N/A"); const weatherStateText = ref("N/A");
@ -13,7 +14,8 @@ const useWeatherDataStore = defineStore("weatherData", () => {
const temperature = ref("N/A"); const temperature = ref("N/A");
const humidity = ref("N/A"); const humidity = ref("N/A");
const actualNighttime = ref(false); const actualNighttime = ref(false);
const dateTime = ref("N/A"); const dateTime = ref(dayjs().format("YYYY-MM-DD HH:mm:ss"));
const intervalId = ref(null);
const subscribers = ref([]); const subscribers = ref([]);
const subscribeToWeather = () => { const subscribeToWeather = () => {
@ -89,22 +91,32 @@ const useWeatherDataStore = defineStore("weatherData", () => {
}; };
const updateTime = () => { const updateTime = () => {
const date = new Date(); dateTime.value = dayjs().format("YYYY-MM-DD HH:mm:ss");
window.require && // const date = new Date();
window.requirejs(["baja!"], (baja) => { // window.require &&
const bAbsTime = baja.AbsTime.make({ jsDate: date }); // window.requirejs(["baja!"], (baja) => {
bAbsTime // const bAbsTime = baja.AbsTime.make({ jsDate: date });
.toDateTimeString() // bAbsTime
.then((dateTimeStr) => { // .toDateTimeString()
dateTime.value = dateTimeStr; // .then((dateTimeStr) => {
}) // dateTime.value = dateTimeStr;
.catch((error) => { // })
console.error("轉換時間字串失敗:", error); // .catch((error) => {
}); // console.error("轉換時間字串失敗:", error);
}); // });
// });
}; };
const clearAllSubscriber = () => { const startUpdateTimeInterval = () => { // 新增啟動 interval 的方法
intervalId.value = setInterval(updateTime, 1000);
};
const stopUpdateTimeInterval = () => { // 新增清除 interval 的方法
clearInterval(intervalId.value);
intervalId.value = null;
};
const clearAllSubscriber = () => {
subscribers.value.forEach((subscriber) => { subscribers.value.forEach((subscriber) => {
subscriber.detach("changed"); subscriber.detach("changed");
}); });
@ -119,9 +131,12 @@ const useWeatherDataStore = defineStore("weatherData", () => {
humidity, humidity,
actualNighttime, actualNighttime,
dateTime, dateTime,
intervalId, // 暴露 intervalId
subscribeToWeather, subscribeToWeather,
updateTime, updateTime,
clearAllSubscriber, clearAllSubscriber,
startUpdateTimeInterval, // 暴露啟動 interval 的方法
stopUpdateTimeInterval,
}; };
}); });

View File

@ -7,3 +7,7 @@
a { a {
color: #69b0cf; color: #69b0cf;
} }
a:hover,
a:active {
color: #69b0cf96;
}

View File

@ -250,7 +250,7 @@ onUnmounted(() => {
</a-col> </a-col>
</a-row> </a-row>
<a-row :gutter="24" class="px-5"> <a-row :gutter="24" class="px-5 pb-5">
<a-col :span="14"> <a-col :span="14">
<!-- 系統小類 --> <!-- 系統小類 -->
<DashboardTag /> <DashboardTag />