路徑修正

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
}

View File

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

View File

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

View File

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

View File

@ -21,7 +21,7 @@ const props = defineProps({
</a-col>
<a-col :span="6" class="pl-0">
<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>
</a-col>
</a-row>

View File

@ -93,13 +93,19 @@ const handleClick = (ord) => {
.card {
box-shadow: 0 20px 27px rgb(0 0 0 / 5%);
}
.inner-card {
background-color: #69b0cf;
}
.inner-card:hover {
opacity: 0.75;
}
h5 {
margin: 0;
font-weight: 700;
font-size: 33px;
font-size: 30px;
color: #141414;
}
</style>

View File

@ -52,7 +52,7 @@ const loadModel = (filePath) => {
onMounted(async () => {
console.log("Forge 加載");
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);
});

View File

@ -65,9 +65,24 @@ watch(
:key="item.key"
@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-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">
<a-menu-item
v-if="!child.children"
@ -101,14 +116,34 @@ watch(
background-color: transparent;
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 {
color: #fff;
}
.sidebarMenu .ant-menu-submenu-title:hover,
.sidebarMenu .ant-menu-item:hover {
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 {
background-color: #e7f5a7 !important;
color: #333 !important;
}
.sidebarMenu .ant-menu-item-selected img {
filter: brightness(0);
}
</style>

View File

@ -56,7 +56,7 @@ onBeforeUnmount(() => {
</template>
<a-badge :count="totalAlarmCount" :overflow-count="999" class="!mt-3">
<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>
</a>
</a-badge>

View File

@ -1,21 +1,24 @@
<script setup>
import { nextTick, onMounted, onUnmounted } from "vue";
import { onMounted, onUnmounted, watch } from "vue";
import useNiagaraDataStore from "@/stores/useNiagaraDataStore";
import useWeatherDataStore from "@/stores/useWeatherDataStore";
const niagaraStore = useNiagaraDataStore();
const weatherStore = useWeatherDataStore();
let intervalId = null;
onMounted(async () => {
console.log('window.require',window.require);
await weatherStore.subscribeToWeather();
//
weatherStore.updateTime();
intervalId = setInterval(weatherStore.updateTime, 1000);
});
watch(
() => niagaraStore.weatherList,
(newValue, oldValue) => {
if (newValue) {
weatherStore.subscribeToWeather();
weatherStore.updateTime();
weatherStore.startUpdateTimeInterval();
}
},
{ immediate: true }
);
onUnmounted(() => {
clearInterval(intervalId);
weatherStore.clearAllSubscriber();
});
</script>

View File

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

View File

@ -13,7 +13,7 @@ const useElecDemandStore = defineStore("elecDemand", () => {
window.requirejs(["baja!"], (baja) => {
let eleclist = [];
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({
cursor: {
before: () => {},
@ -40,7 +40,7 @@ const useElecDemandStore = defineStore("elecDemand", () => {
const subscribeToHistory = (item, index) => {
const slotPath = item.slotPath;
const ordString = `local:|foxs:4918|station:|${slotPath}`;
const ordString = `local:|foxs:|station:|${slotPath}`;
// @ts-ignore
window.require &&

View File

@ -18,7 +18,7 @@ const useElecStore = defineStore("elecData", () => {
console.log("進入 bajaSubscriber 準備執行用電價 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 = [];
@ -45,7 +45,7 @@ const useElecStore = defineStore("elecData", () => {
console.log("進入 bajaSubscriber 準備執行用電度數 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 查詢
let eleclist = [];
@ -85,7 +85,7 @@ const useElecStore = defineStore("elecData", () => {
.endOf("day")
.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);
// @ts-ignore
window.require &&

View File

@ -5,6 +5,7 @@ import {
imagesWeatherNight,
orderWeather,
} from "@/constants";
import dayjs from "dayjs";
const useWeatherDataStore = defineStore("weatherData", () => {
const weatherStateText = ref("N/A");
@ -13,7 +14,8 @@ const useWeatherDataStore = defineStore("weatherData", () => {
const temperature = ref("N/A");
const humidity = ref("N/A");
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 subscribeToWeather = () => {
@ -89,22 +91,32 @@ const useWeatherDataStore = defineStore("weatherData", () => {
};
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);
});
});
dateTime.value = dayjs().format("YYYY-MM-DD HH:mm:ss");
// 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 = () => {
const startUpdateTimeInterval = () => { // 新增啟動 interval 的方法
intervalId.value = setInterval(updateTime, 1000);
};
const stopUpdateTimeInterval = () => { // 新增清除 interval 的方法
clearInterval(intervalId.value);
intervalId.value = null;
};
const clearAllSubscriber = () => {
subscribers.value.forEach((subscriber) => {
subscriber.detach("changed");
});
@ -119,9 +131,12 @@ const useWeatherDataStore = defineStore("weatherData", () => {
humidity,
actualNighttime,
dateTime,
intervalId, // 暴露 intervalId
subscribeToWeather,
updateTime,
clearAllSubscriber,
startUpdateTimeInterval, // 暴露啟動 interval 的方法
stopUpdateTimeInterval,
};
});

View File

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

View File

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