路徑修正
This commit is contained in:
parent
704af2eb18
commit
5555a51579
2
.env
2
.env
@ -1 +1 @@
|
||||
VITE_FILE_API_BASEURL = "https://192.168.0.206:8500"
|
||||
VITE_FILE_API_BASEURL = ".."
|
BIN
public/build.jpg
BIN
public/build.jpg
Binary file not shown.
Before Width: | Height: | Size: 134 KiB |
@ -1,4 +1,3 @@
|
||||
{
|
||||
"systemName": "關渡醫院中央監控",
|
||||
"is3D": true
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 &&
|
||||
|
@ -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 &&
|
||||
|
@ -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,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -7,3 +7,7 @@
|
||||
a {
|
||||
color: #69b0cf;
|
||||
}
|
||||
a:hover,
|
||||
a:active {
|
||||
color: #69b0cf96;
|
||||
}
|
||||
|
@ -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 />
|
||||
|
Loading…
Reference in New Issue
Block a user