Merge branch 'main' into feature/assetMgmt
This commit is contained in:
commit
b48717f091
@ -1,3 +1,3 @@
|
|||||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
||||||
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||||
VITE_FORGE_BASEURL = "http://localhost:5173"
|
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
@ -1,3 +1,3 @@
|
|||||||
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
VITE_API_BASEURL = "https://ibms-cvilux-api.production.mjmtech.com.tw"
|
||||||
VITE_FILE_API_BASEURL = "https://ibms-cvilux.production.mjmtech.com.tw"
|
VITE_FILE_API_BASEURL = "https://cgems.cvilux-group.com:8088"
|
||||||
VITE_FORGE_BASEURL = "http://202.39.218.221:8080/file/netzero"
|
VITE_FORGE_BASEURL = "https://cgems.cvilux-group.com:8088/dist"
|
44
public/config.json
Normal file
44
public/config.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"heatmap": {
|
||||||
|
"temp": {
|
||||||
|
"range": [0, 50],
|
||||||
|
"color": ["#0023F5", "#FF1C05"],
|
||||||
|
"unit": "°C"
|
||||||
|
},
|
||||||
|
"humi": {
|
||||||
|
"range": [15, 95],
|
||||||
|
"color": ["#ADD8E6", "#00008B"],
|
||||||
|
"unit": "%"
|
||||||
|
},
|
||||||
|
"CO2": {
|
||||||
|
"range": [0, 5000],
|
||||||
|
"color": ["#FFDAB9", "#FF8C00"],
|
||||||
|
"unit": "ppm"
|
||||||
|
},
|
||||||
|
"CO": {
|
||||||
|
"range": [0, 1000],
|
||||||
|
"color": ["#FFFFE0", "#FFD700"],
|
||||||
|
"unit": "ppm"
|
||||||
|
},
|
||||||
|
"CH2O": {
|
||||||
|
"range": [0, 100],
|
||||||
|
"color": ["#90EE90", "#006400"],
|
||||||
|
"unit": "ppb"
|
||||||
|
},
|
||||||
|
"PM1": {
|
||||||
|
"range": [0, 20],
|
||||||
|
"color": ["#E6E6FA", "#800080"],
|
||||||
|
"unit": "µg/m³"
|
||||||
|
},
|
||||||
|
"PM2.5": {
|
||||||
|
"range": [0, 55],
|
||||||
|
"color": ["#FFB6C1", "#FF0000"],
|
||||||
|
"unit": "µg/m³"
|
||||||
|
},
|
||||||
|
"PM10": {
|
||||||
|
"range": [0, 150],
|
||||||
|
"color": ["#FFDDC1", "#FF1493"],
|
||||||
|
"unit": "µg/m³"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -65,4 +65,16 @@
|
|||||||
.btn-text-without-border {
|
.btn-text-without-border {
|
||||||
@apply active:border-0 focus:border-0 focus-visible:border-0 active:outline-none focus:outline-none focus-visible:outline-none;
|
@apply active:border-0 focus:border-0 focus-visible:border-0 active:outline-none focus:outline-none focus-visible:outline-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-add {
|
||||||
|
@apply text-white border border-cyan-400 bg-cyan-400 hover:bg-[theme("colors.cyan.500")]
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-search {
|
||||||
|
@apply text-white border border-sky-400 bg-sky-400 hover:bg-[theme("colors.sky.500")]
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-export {
|
||||||
|
@apply text-white border border-emerald-400 bg-emerald-400 hover:bg-[theme("colors.emerald.500")]
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,24 +5,40 @@ import { twMerge } from "tailwind-merge";
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
items: Array,
|
items: Array,
|
||||||
withLine: Boolean,
|
withLine: Boolean,
|
||||||
|
withBtnClass: { type: Boolean, default: false },
|
||||||
// this is for change active button
|
// this is for change active button
|
||||||
onclick: Function,
|
onclick: Function,
|
||||||
className: String
|
className: String,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-wrap text-white items-center">
|
<div class="flex flex-wrap text-white items-center">
|
||||||
<button v-for="item in items" :class="twMerge(
|
<button
|
||||||
'btn my-1',
|
v-for="item in items"
|
||||||
item.active ? 'btn-success' : 'btn-outline-success',
|
:class="
|
||||||
withLine ? 'line' : 'mx-2 first:ml-0 ',
|
twMerge(
|
||||||
className
|
'btn my-1',
|
||||||
)
|
withBtnClass
|
||||||
" :disabled="item.disabled" :key="item.key" @click.stop.prevent="(e) => {
|
? item.btn
|
||||||
|
: item.active
|
||||||
|
? 'btn-success'
|
||||||
|
: 'btn-outline-success',
|
||||||
|
withLine ? 'line' : 'mx-2 first:ml-0 ',
|
||||||
|
className
|
||||||
|
)
|
||||||
|
"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
:key="item.key"
|
||||||
|
@click.stop.prevent="
|
||||||
|
(e) => {
|
||||||
item.onClick ? item.onClick(e, item) : onclick(e, item);
|
item.onClick ? item.onClick(e, item) : onclick(e, item);
|
||||||
}
|
}
|
||||||
">
|
"
|
||||||
|
>
|
||||||
|
<span v-if="withBtnClass">
|
||||||
|
<font-awesome-icon :icon="['fas', item.icon]" class=" text-lg" />
|
||||||
|
</span>
|
||||||
<slot name="buttonContent" v-bind="{ record: item }">
|
<slot name="buttonContent" v-bind="{ record: item }">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</slot>
|
</slot>
|
||||||
|
@ -161,7 +161,7 @@ watch(
|
|||||||
<div :class="withStyle ? 'content-box' : 'py-5'">
|
<div :class="withStyle ? 'content-box' : 'py-5'">
|
||||||
<div class="content-decoration">
|
<div class="content-decoration">
|
||||||
<slot name="beforeTable"></slot>
|
<slot name="beforeTable"></slot>
|
||||||
<form ref="form">
|
<form ref="form " class="overflow-x-auto">
|
||||||
<table
|
<table
|
||||||
:class="
|
:class="
|
||||||
twMerge(
|
twMerge(
|
||||||
@ -322,14 +322,17 @@ watch(
|
|||||||
<style lang="css" scoped>
|
<style lang="css" scoped>
|
||||||
/**資料框**/
|
/**資料框**/
|
||||||
.content-box {
|
.content-box {
|
||||||
@apply border border-info p-1 relative mb-4 bg-transparent;
|
@apply border border-info p-1 relative mb-4 bg-transparent ;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-box .table {
|
.content-box .table {
|
||||||
@apply rounded-none;
|
@apply rounded-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table th,
|
.table th {
|
||||||
|
@apply bg-cyan-600 bg-opacity-30 border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
|
||||||
|
}
|
||||||
|
|
||||||
.table td {
|
.table td {
|
||||||
@apply border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
|
@apply border-r border-b border-white text-lg font-semibold text-white text-center px-2 py-3;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import useSystemStatusByBaja from "@/hooks/baja/useSystemStatusByBaja";
|
|||||||
import ForgeInfoModal from "../../views/system/components/SystemInfoModal.vue";
|
import ForgeInfoModal from "../../views/system/components/SystemInfoModal.vue";
|
||||||
import useAlarmStore from "@/stores/useAlarmStore";
|
import useAlarmStore from "@/stores/useAlarmStore";
|
||||||
import useForgeSprite from "@/hooks/forge/useForgeSprite";
|
import useForgeSprite from "@/hooks/forge/useForgeSprite";
|
||||||
|
import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
initialData: Object,
|
initialData: Object,
|
||||||
@ -27,13 +28,9 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const store = useHeatmapBarStore();
|
||||||
|
|
||||||
const heat_bar_isShow = ref(false);
|
const { updateDataVisualization, createSprites, showSubSystemObjects, forgeClickListener, clear } = useForgeSprite()
|
||||||
const updateHeatBarIsShow = (isShow) => {
|
|
||||||
heat_bar_isShow.value = isShow;
|
|
||||||
};
|
|
||||||
|
|
||||||
const { updateDataVisualization, createSprites, hideAllObjects, forgeClickListener, clear } = useForgeSprite()
|
|
||||||
|
|
||||||
const forgeDom = ref(null);
|
const forgeDom = ref(null);
|
||||||
|
|
||||||
@ -92,9 +89,10 @@ const loadModel = (viewer, filePath) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// const loadModel = (viewer, urn) => {
|
// const loadModel = (viewer) => {
|
||||||
// return new Promise(function (resolve, reject) {
|
// return new Promise(function (resolve, reject) {
|
||||||
// async function onDocumentLoadSuccess(doc) {
|
// async function onDocumentLoadSuccess(doc) {
|
||||||
|
// console.log("模型加載完成");
|
||||||
// viewer.setGroundShadow(false);
|
// viewer.setGroundShadow(false);
|
||||||
// viewer.impl.renderer().setClearAlpha(0); //clear alpha channel
|
// viewer.impl.renderer().setClearAlpha(0); //clear alpha channel
|
||||||
// viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter
|
// viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter
|
||||||
@ -163,7 +161,7 @@ const initForge = async () => {
|
|||||||
viewer.isLoadDone()
|
viewer.isLoadDone()
|
||||||
);
|
);
|
||||||
|
|
||||||
hideAllObjects();
|
showSubSystemObjects();
|
||||||
createSprites();
|
createSprites();
|
||||||
forgeClickListener();
|
forgeClickListener();
|
||||||
})
|
})
|
||||||
@ -201,22 +199,18 @@ onUnmounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<ForgeInfoModal :data="currentInfoModalData" />
|
<ForgeInfoModal :data="currentInfoModalData" />
|
||||||
<div id="forge-preview" ref="forgeDom" class="relative w-full h-full min-h-full">
|
<div id="forge-preview" ref="forgeDom" class="relative w-full h-full min-h-full">
|
||||||
<div v-show="heat_bar_isShow" class="absolute z-10 heatbar">
|
<div v-show="store.heat_bar_isShow" class="absolute z-10 heatbar">
|
||||||
<div class="w-40 flex justify-between text-[10px] mb-1">
|
<div class="w-40 flex justify-between text-[10px] mb-1">
|
||||||
<span class="text-gradient-1">10 °C</span>
|
<span v-for="value in store.heatmapConfig?.range" class="text-gradient-1">{{ value }} {{
|
||||||
<span class="text-gradient-2">20 °C</span>
|
store.heatmapConfig?.unit }}</span>
|
||||||
<span class="text-gradient-3">30 °C</span>
|
|
||||||
<span class="text-gradient-4">40 °C</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="w-40 h-3" style="
|
<div class="w-40 h-3" :style="{
|
||||||
background: linear-gradient(
|
background: `linear-gradient(
|
||||||
to right,
|
to right,
|
||||||
#0000ff 0%,
|
${store.heatmapConfig?.color[0]} 0%,
|
||||||
#00ff00 33%,
|
${store.heatmapConfig?.color[1]} 100%
|
||||||
#ffff00 66%,
|
)`
|
||||||
#ff0000 100%
|
}"></div>
|
||||||
);
|
|
||||||
"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- label -->
|
<!-- label -->
|
||||||
<!-- https://github.com/augustogoncalves/forge-plant-operation/blob/master/forgeSample/wwwroot/js/iconExtension.js -->
|
<!-- https://github.com/augustogoncalves/forge-plant-operation/blob/master/forgeSample/wwwroot/js/iconExtension.js -->
|
||||||
@ -264,11 +258,11 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.homeViewWrapper {
|
.homeViewWrapper {
|
||||||
transform: scale(0.9) !important;
|
transform: scale(2) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heatbar {
|
.heatbar {
|
||||||
right: v-bind("`${props.cubeStyle.right + 2}%`") !important;
|
/* right: v-bind("`${props.cubeStyle.right + 2}%`") !important; */
|
||||||
top: 0% !important;
|
top: 0% !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,10 +5,13 @@ import { getAuth, getAllSysSidebar } from "@/apis/building";
|
|||||||
import useBuildingStore from "@/stores/useBuildingStore";
|
import useBuildingStore from "@/stores/useBuildingStore";
|
||||||
import useUserInfoStore from "@/stores/useUserInfoStore";
|
import useUserInfoStore from "@/stores/useUserInfoStore";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
|
|
||||||
const { locale } = useI18n();
|
const { locale } = useI18n();
|
||||||
const store = useUserInfoStore();
|
const store = useUserInfoStore();
|
||||||
const buildingStore = useBuildingStore();
|
const buildingStore = useBuildingStore();
|
||||||
|
const route = useRoute();
|
||||||
const openKeys = ref([]); // 追蹤當前打開的子菜單
|
const openKeys = ref([]); // 追蹤當前打開的子菜單
|
||||||
|
|
||||||
const iniFroList = async () => {
|
const iniFroList = async () => {
|
||||||
@ -18,9 +21,9 @@ const iniFroList = async () => {
|
|||||||
res.data.map((d) =>
|
res.data.map((d) =>
|
||||||
AUTHPAGES.find(({ authCode }) => authCode === d.authCode)
|
AUTHPAGES.find(({ authCode }) => authCode === d.authCode)
|
||||||
? {
|
? {
|
||||||
...d,
|
...d,
|
||||||
...AUTHPAGES.find(({ authCode }) => authCode === d.authCode),
|
...AUTHPAGES.find(({ authCode }) => authCode === d.authCode),
|
||||||
}
|
}
|
||||||
: d
|
: d
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -71,38 +74,93 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<ul class="px-1 menu-box my-2">
|
<ul class="px-1 menu-box my-2">
|
||||||
<li class="flex flex-col items-center justify-center">
|
<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">
|
<router-link
|
||||||
<font-awesome-icon :icon="['fas', 'home']" size="2x" class="w-10 m-auto" />
|
: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") }}
|
{{ $t("home") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-for="page in authPages" class="flex flex-col items-center justify-center">
|
<li
|
||||||
<a v-if="page.authCode === 'PF1'" @click="showDrawer"
|
v-for="page in authPages"
|
||||||
class="flex flex-col justify-center items-center btn-group text-white cursor-pointer">
|
class="flex flex-col items-center justify-center"
|
||||||
<font-awesome-icon :icon="['fas', page.icon]" size="2x" class="w-10 m-auto" />
|
>
|
||||||
|
<a
|
||||||
|
v-if="page.authCode === 'PF1'"
|
||||||
|
@click="showDrawer"
|
||||||
|
:class="
|
||||||
|
twMerge(
|
||||||
|
'flex flex-col justify-center items-center btn-group text-white cursor-pointer',
|
||||||
|
route.fullPath.includes('/system')
|
||||||
|
? 'router-link-active router-link-exact-active'
|
||||||
|
: ''
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<font-awesome-icon
|
||||||
|
:icon="['fas', page.icon]"
|
||||||
|
size="2x"
|
||||||
|
class="w-10 m-auto"
|
||||||
|
/>
|
||||||
{{ page.subName }}
|
{{ page.subName }}
|
||||||
</a>
|
</a>
|
||||||
<router-link v-else :to="page.navigate" type="link"
|
<router-link
|
||||||
class="flex flex-col justify-center items-center btn-group text-white">
|
v-else
|
||||||
<font-awesome-icon :icon="['fas', page.icon]" size="2x" class="w-10 m-auto" />
|
: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 }}
|
{{ page.subName }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<a-drawer :width="250" placement="left" :open="open" :closable="false" @close="onClose" class="sub-drawer"
|
<a-drawer
|
||||||
:maskStyle="{ opacity: 0 }" :bodyStyle="{ paddingLeft: 0, paddingRight: 0 }">
|
:width="250"
|
||||||
<a-menu mode="inline" theme="dark" class="text-lg bg-transparent" :openKeys="openKeys"
|
placement="left"
|
||||||
@openChange="handleOpenChange">
|
:open="open"
|
||||||
<a-sub-menu v-for="main in buildingStore.mainSubSys" :key="main.main_system_tag" :title="main.full_name">
|
:closable="false"
|
||||||
<a-menu-item v-for="sub in main.history_Sub_systems" :key="sub.sub_system_tag" @click="() => onClose()">
|
@close="onClose"
|
||||||
<router-link :to="{
|
class="sub-drawer"
|
||||||
name: 'sub_system',
|
:maskStyle="{ opacity: 0 }"
|
||||||
params: {
|
:bodyStyle="{ paddingLeft: 0, paddingRight: 0 }"
|
||||||
main_system_id: main.main_system_tag,
|
>
|
||||||
sub_system_id: sub.sub_system_tag,
|
<a-menu
|
||||||
floor_id: 'main'
|
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,
|
||||||
|
floor_id: 'main',
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
>
|
||||||
{{ sub.full_name }}
|
{{ sub.full_name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@ -115,28 +173,17 @@ onMounted(() => {
|
|||||||
color: #93c0dc;
|
color: #93c0dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-menu-submenu-title:active) {
|
:deep(.ant-menu-submenu-selected) {
|
||||||
color: #35759d !important;
|
.ant-menu-submenu-title {
|
||||||
background-color: transparent !important;
|
@apply text-info;
|
||||||
}
|
|
||||||
|
|
||||||
:deep .ant-menu-item:not(.ant-menu-item-selected) {
|
|
||||||
&::before {
|
|
||||||
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10 grayscale;
|
|
||||||
content: "";
|
|
||||||
background: url(@ASSET/img/chart-data-background03.svg) center center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background-color: transparent !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep .ant-menu-item-selected {
|
:deep(.ant-menu-item-selected) {
|
||||||
@apply bg-transparent relative;
|
@apply bg-transparent relative;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat z-10;
|
@apply absolute w-[15px] h-[15px] bottom-3.5 left-7 bg-no-repeat saturate-200 z-10;
|
||||||
content: "";
|
content: "";
|
||||||
background: url(@ASSET/img/chart-data-background03.svg) center center;
|
background: url(@ASSET/img/chart-data-background03.svg) center center;
|
||||||
}
|
}
|
||||||
@ -146,7 +193,7 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #89d2ff !important;
|
color: #35ecec !important;
|
||||||
text-shadow: 0px 0px 1px #fff;
|
text-shadow: 0px 0px 1px #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,8 @@
|
|||||||
"new_category": "新类别",
|
"new_category": "新类别",
|
||||||
"index": "编号",
|
"index": "编号",
|
||||||
"oriOrgName": "档案",
|
"oriOrgName": "档案",
|
||||||
"operation": "功能"
|
"operation": "功能",
|
||||||
|
"upload": "图资上传"
|
||||||
},
|
},
|
||||||
"assetManagement": {
|
"assetManagement": {
|
||||||
"title": "资产管理",
|
"title": "资产管理",
|
||||||
|
@ -180,7 +180,8 @@
|
|||||||
"new_category": "新類別",
|
"new_category": "新類別",
|
||||||
"index": "編號",
|
"index": "編號",
|
||||||
"oriOrgName": "檔案",
|
"oriOrgName": "檔案",
|
||||||
"operation": "功能"
|
"operation": "功能",
|
||||||
|
"upload": "圖資上傳"
|
||||||
},
|
},
|
||||||
"assetManagement": {
|
"assetManagement": {
|
||||||
"title": "資產管理",
|
"title": "資產管理",
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
"category": "Category",
|
"category": "Category",
|
||||||
"value": "Value",
|
"value": "Value",
|
||||||
"date": "Record Time",
|
"date": "Record Time",
|
||||||
"point": "Point",
|
"point": "Character",
|
||||||
"combinations": "Common combinations",
|
"combinations": "Common combinations",
|
||||||
"date_range": "Date range",
|
"date_range": "Date Range",
|
||||||
"time_range": "Time interval",
|
"time_range": "Time interval",
|
||||||
"start_date": "Start date",
|
"start_date": "Start date",
|
||||||
"start_time": "Start time",
|
"start_time": "Start time",
|
||||||
@ -73,26 +73,26 @@
|
|||||||
"confirm": "Confirm"
|
"confirm": "Confirm"
|
||||||
},
|
},
|
||||||
"alert": {
|
"alert": {
|
||||||
"query_title": "Alarm record query",
|
"query_title": "Alarm Record Query",
|
||||||
"setting_title": "Alarm settings",
|
"setting_title": "Alarm Settings",
|
||||||
"offnormal": "off normal",
|
"offnormal": "Off Normal",
|
||||||
"normal": "normal",
|
"normal": "Normal",
|
||||||
"unacked": "unacked",
|
"unacked": "Unacked",
|
||||||
"acked": "acked",
|
"acked": "Acked",
|
||||||
"30days": "Last 30 days",
|
"30days": "Last 30 Days",
|
||||||
"start_date": "Start date",
|
"start_date": "Start Date",
|
||||||
"end_date": "End date",
|
"end_date": "End Date",
|
||||||
"building_and_floor": "Building - floor",
|
"building_and_floor": "Building - Floor",
|
||||||
"uuid": "Exception ID",
|
"uuid": "Exception ID",
|
||||||
"alarmClass": "Exception Category",
|
"alarmClass": "Exception Category",
|
||||||
"device_name": "Device name",
|
"device_name": "Device Name",
|
||||||
"device_number": "Device number",
|
"device_number": "Device Number",
|
||||||
"date": "Occurrence date",
|
"date": "Occurrence Date",
|
||||||
"time": "Occurrence time",
|
"time": "Occurrence Time",
|
||||||
"error_msg": "Abnormal cause",
|
"error_msg": "Abnormal Cause",
|
||||||
"ack_state": "Ack Confirm",
|
"ack_state": "Ack Confirm",
|
||||||
"repair_order_number": "Repair order number",
|
"repair_order_number": "Repair Order Number",
|
||||||
"repair_order": "Repair order",
|
"repair_order": "Repair Order",
|
||||||
"form_number": "Form Number",
|
"form_number": "Form Number",
|
||||||
"start_time": "Estimated Start Time",
|
"start_time": "Estimated Start Time",
|
||||||
"item": "Item",
|
"item": "Item",
|
||||||
@ -102,59 +102,59 @@
|
|||||||
"repair_item_code": "Repair Item Code (Device Number)",
|
"repair_item_code": "Repair Item Code (Device Number)",
|
||||||
"responsible_vendor": "Responsible Vendor",
|
"responsible_vendor": "Responsible Vendor",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"not_completed": "Not completed",
|
"not_completed": "Not Completed",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"worker_id": "Worker ID",
|
"worker_id": "Worker ID",
|
||||||
"notice": "Notice",
|
"notice": "Notice",
|
||||||
"result_description": "Result Description",
|
"result_description": "Result Description",
|
||||||
"upload_file": "Upload File",
|
"upload_file": "Upload File",
|
||||||
"enable": "Enable",
|
"enable": "Enable",
|
||||||
"not_enabled": "Not enabled",
|
"not_enabled": "Not Enabled",
|
||||||
"qualifications": "Qualifications",
|
"qualifications": "Qualifications",
|
||||||
"upper_limit": "Upper limit",
|
"upper_limit": "Upper Limit",
|
||||||
"lower_limit": "Lower limit",
|
"lower_limit": "Lower Limit",
|
||||||
"highDelay": "Max duration (s)",
|
"highDelay": "Max Duration (s)",
|
||||||
"lowDelay": "Min duration (s)",
|
"lowDelay": "Min Duration (s)",
|
||||||
"warning_method": "Warning method",
|
"warning_method": "Warning Method",
|
||||||
"warning_time": "Warning time",
|
"warning_time": "Warning Time",
|
||||||
"operation": "Function",
|
"operation": "Function",
|
||||||
"alarm_settings": "Abnormal alarm settings",
|
"alarm_settings": "Abnormal Alarm Settings",
|
||||||
"time_setting": "Time setting",
|
"time_setting": "Time Setting",
|
||||||
"yes": "yes",
|
"yes": "Yes",
|
||||||
"no": "no",
|
"no": "No",
|
||||||
"no_notify": "No notification",
|
"no_notify": "No Notification",
|
||||||
"notify_name": "Name",
|
"notify_name": "Name",
|
||||||
"notify_phone": "Phone number",
|
"notify_phone": "Phone Number",
|
||||||
"notify_email": "email",
|
"notify_email": "Email",
|
||||||
"notify_items": "Notification items",
|
"notify_items": "Notification Items",
|
||||||
"notify_list": "Notification list",
|
"notify_list": "Notification List",
|
||||||
"choose": "choose"
|
"choose": "Choose"
|
||||||
},
|
},
|
||||||
"operation": {
|
"operation": {
|
||||||
"title": "Operation and maintenance management",
|
"title": "Operation And Maintenance Management",
|
||||||
"project": "Project",
|
"project": "Project",
|
||||||
"location": "Location",
|
"location": "Location",
|
||||||
"uuid": "Exception ID",
|
"uuid": "Exception ID",
|
||||||
"form_number": "Form Number",
|
"form_number": "Form Number",
|
||||||
"device_name": "Device name",
|
"device_name": "Device Name",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"staff": "Staff",
|
"staff": "Staff",
|
||||||
"start_time": "Estimated start time",
|
"start_time": "Estimated Start Time",
|
||||||
"upload": "File upload",
|
"upload": "File Upload",
|
||||||
"finish_time": "Completion time",
|
"finish_time": "Completion Time",
|
||||||
"operation": "Function",
|
"operation": "Function",
|
||||||
"vendor": "company",
|
"vendor": "Company",
|
||||||
"contact_person": "Contact person",
|
"contact_person": "Contact Person",
|
||||||
"phone": "Phone",
|
"phone": "Phone",
|
||||||
"email": "email",
|
"email": "Email",
|
||||||
"created_at": "Creation date",
|
"created_at": "Creation Date",
|
||||||
"maintainance": "Maintainance",
|
"maintenance": "Maintenance",
|
||||||
"repair": "Repair",
|
"repair": "Repair",
|
||||||
"company_info": "Company Info",
|
"company_info": "Company Info",
|
||||||
"repair_item": "Repair Item",
|
"repair_item": "Repair Item",
|
||||||
"repair_item_code": "Repair Item Code (Device Number)",
|
"repair_item_code": "Repair Item Code (Device Number)",
|
||||||
"responsible_vendor": "Responsible Vendor",
|
"responsible_vendor": "Responsible Vendor",
|
||||||
"not_completed": "Not completed",
|
"not_completed": "Not Completed",
|
||||||
"completed": "Completed",
|
"completed": "Completed",
|
||||||
"worker_id": "Worker ID",
|
"worker_id": "Worker ID",
|
||||||
"notice": "Notice",
|
"notice": "Notice",
|
||||||
@ -163,36 +163,37 @@
|
|||||||
"name": "Name",
|
"name": "Name",
|
||||||
"city": "City",
|
"city": "City",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
"tax_id_number": "tax ID number",
|
"tax_id_number": "Tax ID Number",
|
||||||
"remark": "Remark",
|
"remark": "Remark",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"serial": "Order number",
|
"serial": "Order Number",
|
||||||
"today": "Today",
|
"today": "Today",
|
||||||
"yesterday": "Yesterday",
|
"yesterday": "Yesterday",
|
||||||
"start_created_at": "Start date",
|
"start_created_at": "Start Date",
|
||||||
"end_created_at": "End date",
|
"end_created_at": "End Date",
|
||||||
"enter_text": "Please enter text",
|
"enter_text": "Please enter text",
|
||||||
"enter_serial": "Please enter the order number"
|
"enter_serial": "Please enter the order number"
|
||||||
},
|
},
|
||||||
"graphManagement": {
|
"graphManagement": {
|
||||||
"title": "Data and Publication Management",
|
"title": "Data And Publication Management",
|
||||||
"category": "Category",
|
"category": "Category",
|
||||||
"new_category": "New category",
|
"new_category": "New Category",
|
||||||
"index": "serial number",
|
"index": "Serial Number",
|
||||||
"oriOrgName": "file",
|
"oriOrgName": "File",
|
||||||
"operation": "Function"
|
"operation": "Function",
|
||||||
|
"upload": "Upload"
|
||||||
},
|
},
|
||||||
"assetManagement": {
|
"assetManagement": {
|
||||||
"title": "Asset Management",
|
"title": "Asset Management",
|
||||||
"add_category": "Add category",
|
"add_category": "Add Category",
|
||||||
"system_name": "Name",
|
"system_name": "Name",
|
||||||
"system_value": "Code",
|
"system_value": "Code",
|
||||||
"system_parent": "Category",
|
"system_parent": "Category",
|
||||||
"device_number": "Device number",
|
"device_number": "Device Number",
|
||||||
"device_name": "Device name",
|
"device_name": "Device Name",
|
||||||
"asset_number": "Asset number",
|
"asset_number": "Asset Number",
|
||||||
"floor": "Location",
|
"floor": "Location",
|
||||||
"add_floor": "Add floor",
|
"add_floor": "Add Floor",
|
||||||
"add_floor_text": "Floor map must be uploaded first",
|
"add_floor_text": "Floor map must be uploaded first",
|
||||||
"device_coordinate": "Coordinate",
|
"device_coordinate": "Coordinate",
|
||||||
"brand_and_modal": "Brand/Model",
|
"brand_and_modal": "Brand/Model",
|
||||||
@ -200,44 +201,44 @@
|
|||||||
"modal": "Model",
|
"modal": "Model",
|
||||||
"company_and_contact": "Company/Contact Person",
|
"company_and_contact": "Company/Contact Person",
|
||||||
"company": "Company",
|
"company": "Company",
|
||||||
"buying_date": "Purchase time",
|
"buying_date": "Purchase Time",
|
||||||
"oriFile": "File upload",
|
"oriFile": "File Upload",
|
||||||
"created_at": "Creation time",
|
"created_at": "Creation Time",
|
||||||
"operation": "Function",
|
"operation": "Function",
|
||||||
"device_list": "Device list",
|
"device_list": "Device List",
|
||||||
"edit_device": "Edit device",
|
"edit_device": "Edit Device",
|
||||||
"add_device": "Add device",
|
"add_device": "Add Device",
|
||||||
"operate_text": "Display name",
|
"operate_text": "Display name",
|
||||||
"fill_text": "Please fill it in by system personnel",
|
"fill_text": "Please fill it in by system personnel",
|
||||||
"equipment_point": "Equipment point",
|
"equipment_point": "Equipment Point",
|
||||||
"point": "Point",
|
"point": "Point",
|
||||||
"add_sensor": "Add new sensor",
|
"add_sensor": "Add New Sensor",
|
||||||
"associated_device": "Associated devices",
|
"associated_device": "Associated Devices",
|
||||||
"choose": "Choose",
|
"choose": "Choose",
|
||||||
"index": "serial number",
|
"index": "Serial Number",
|
||||||
"floor_plan": "Floor plan"
|
"floor_plan": "Floor Plan"
|
||||||
},
|
},
|
||||||
"accountManagement": {
|
"accountManagement": {
|
||||||
"account_title": "Account Management",
|
"account_title": "Account Management",
|
||||||
"role_title": "Role Management",
|
"role_title": "Role Management",
|
||||||
"index": "serial number",
|
"index": "Serial Number",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"account": "Account",
|
"account": "Account",
|
||||||
"password": "Password",
|
"password": "Password",
|
||||||
"role": "Role",
|
"role": "Role",
|
||||||
"role_name": "Role name",
|
"role_name": "Role Name",
|
||||||
"role_permissions": "Role permissions",
|
"role_permissions": "Role Permissions",
|
||||||
"role_permissions_setting": "Role permissions settings",
|
"role_permissions_setting": "Role Permissions Settings",
|
||||||
"permission_name": "Permission name",
|
"permission_name": "Permission Name",
|
||||||
"basic_permissions": "Basic permissions",
|
"basic_permissions": "Basic Ppermissions",
|
||||||
"production_permissions": "Production setting permissions",
|
"production_permissions": "Production Setting Permissions",
|
||||||
"email": "email",
|
"email": "Email",
|
||||||
"phone": "Phone",
|
"phone": "Phone",
|
||||||
"created_at": "Created time",
|
"created_at": "Created Time",
|
||||||
"operation": "Function",
|
"operation": "Function",
|
||||||
"name_placeholder": "Please enter user name",
|
"name_placeholder": "Please enter user name",
|
||||||
"role_placeholder": "Please enter the role name",
|
"role_placeholder": "Please enter the role name",
|
||||||
"change_password": "Change password",
|
"change_password": "Change Password",
|
||||||
"choose": "Choose"
|
"choose": "Choose"
|
||||||
},
|
},
|
||||||
"button": {
|
"button": {
|
||||||
|
@ -56,7 +56,8 @@ import {
|
|||||||
faWind,
|
faWind,
|
||||||
faEye,
|
faEye,
|
||||||
faEyeSlash,
|
faEyeSlash,
|
||||||
faGlobe
|
faGlobe,
|
||||||
|
faDownload
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
/* add icons to the library */
|
/* add icons to the library */
|
||||||
@ -114,7 +115,8 @@ library.add(
|
|||||||
faWind,
|
faWind,
|
||||||
faEye,
|
faEye,
|
||||||
faEyeSlash,
|
faEyeSlash,
|
||||||
faGlobe
|
faGlobe,
|
||||||
|
faDownload
|
||||||
);
|
);
|
||||||
|
|
||||||
export default library;
|
export default library;
|
||||||
|
@ -1,70 +1,112 @@
|
|||||||
|
import useSelectedFloor from "@/hooks/useSelectedFloor";
|
||||||
|
import { watch, ref, inject } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
function useForgeFloor() {
|
function useForgeFloor() {
|
||||||
const findLevels = (viewer) => {
|
const route = useRoute();
|
||||||
return new Promise((resolve, reject) => {
|
const levelList = ref([]);
|
||||||
viewer.model.search(
|
const { selectedFloor } = useSelectedFloor();
|
||||||
"layer",
|
const { subscribeData } = inject("system_deviceList");
|
||||||
(nodeIds) => {
|
|
||||||
let levels = [];
|
const forgeViewer = ref(null);
|
||||||
const tree = viewer.model.getInstanceTree();
|
const dataVizExtn = ref(null);
|
||||||
for (let i = 0; i < nodeIds.length; i++) {
|
const updateViewerFloor = (viewer, dataVisualization) => {
|
||||||
const dbId = nodeIds[i];
|
forgeViewer.value = viewer;
|
||||||
const name = tree.getNodeName(dbId);
|
dataVizExtn.value = dataVisualization;
|
||||||
if (!name || name.includes("<沒有層級>")) continue;
|
|
||||||
levels.push({
|
|
||||||
guid: dbId,
|
|
||||||
name,
|
|
||||||
dbId,
|
|
||||||
extension: {
|
|
||||||
buildingStory: true,
|
|
||||||
structure: false,
|
|
||||||
computationHeight: 0,
|
|
||||||
groundPlane: false,
|
|
||||||
hasAssociatedViewPlans: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
levels = levels.sort((a, b) => b.elevation - a.elevation);
|
|
||||||
resolve(levels);
|
|
||||||
},
|
|
||||||
(e) => {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// function getCutPlaneParam(idx, n, viewer, levels) {
|
const findLevels = () => {
|
||||||
// if (idx < 0 || !n) return;
|
forgeViewer.value.model.search(
|
||||||
|
"layer",
|
||||||
|
(nodeIds) => {
|
||||||
|
let levels = [];
|
||||||
|
const tree = forgeViewer.value.model.getInstanceTree();
|
||||||
|
for (let i = 0; i < nodeIds.length; i++) {
|
||||||
|
const dbId = nodeIds[i];
|
||||||
|
const name = tree.getNodeName(dbId);
|
||||||
|
if (!name || name.includes("<沒有層級>")) continue;
|
||||||
|
levels.push({
|
||||||
|
guid: dbId,
|
||||||
|
name,
|
||||||
|
dbId,
|
||||||
|
extension: {
|
||||||
|
buildingStory: true,
|
||||||
|
structure: false,
|
||||||
|
computationHeight: 0,
|
||||||
|
groundPlane: false,
|
||||||
|
hasAssociatedViewPlans: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
levels = levels.sort((a, b) => b.elevation - a.elevation);
|
||||||
|
console.log(levels);
|
||||||
|
levelList.value = levels;
|
||||||
|
},
|
||||||
|
(e) => {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
// const level = levels[idx];
|
watch(forgeViewer, () => {
|
||||||
// if (!level) return;
|
findLevels();
|
||||||
|
});
|
||||||
|
|
||||||
// const model = viewer.model;
|
const hideDbIdFn = () => {
|
||||||
// const globalOffset = model.getData().globalOffset;
|
const tree = forgeViewer.value?.model.getInstanceTree();
|
||||||
// const units = model.getUnitString();
|
const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex);
|
||||||
// const elevRaw = Autodesk.Viewing.Private.convertUnits(
|
for (var i = 0; i < allDbIdsStr.length; i++) {
|
||||||
// "ft",
|
forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
|
||||||
// units,
|
}
|
||||||
// 1,
|
};
|
||||||
// level.elevation
|
const showDbIdFn = () => {
|
||||||
// );
|
hideDbIdFn();
|
||||||
// let d = elevRaw - globalOffset.z - 0.5;
|
subscribeData.value.forEach((value, index) => {
|
||||||
// if (n == 1) d = -1 * d;
|
forgeViewer.value.show(value.forge_dbid);
|
||||||
|
});
|
||||||
|
|
||||||
// return new THREE.Vector4(0, 0, n, d);
|
forgeViewer.value.impl.invalidate(true);
|
||||||
// }
|
};
|
||||||
|
|
||||||
// function profile(viewer, levels) {
|
const showLevels = () => {
|
||||||
// //const upperIdx = 6;
|
if (forgeViewer.value) {
|
||||||
// const upperCutPlaneParam = getCutPlaneParam(2, 1, viewer, levels);
|
const currentFloorName =
|
||||||
// //const lowerIdx = 7;
|
selectedFloor.value?.title?.replaceAll(/U/gi, "") || "";
|
||||||
// const lowerCutPlaneParam = getCutPlaneParam(3, -1, viewer, levels);
|
|
||||||
// viewer.setCutPlanes([upperCutPlaneParam, lowerCutPlaneParam]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
const level = levelList.value.find(({ name }) =>
|
||||||
|
name.includes(currentFloorName)
|
||||||
|
);
|
||||||
|
console.log(currentFloorName, level);
|
||||||
|
|
||||||
|
if (!level) {
|
||||||
|
forgeViewer.value?.impl.toggleGhosting(true);
|
||||||
|
forgeViewer.value?.fitToView([forgeViewer.value.model.getRootId()]);
|
||||||
|
showDbIdFn();
|
||||||
|
} else {
|
||||||
|
hideDbIdFn();
|
||||||
|
// forgeViewer.value.clearSelection();
|
||||||
|
// forgeViewer.value.model.setAllVisibility(0);
|
||||||
|
forgeViewer.value.impl.toggleGhosting(false);
|
||||||
|
// forgeViewer.value.impl.toggleGroundShadow(false);
|
||||||
|
forgeViewer.value.show(level.dbId);
|
||||||
|
forgeViewer.value.impl.invalidate(true);
|
||||||
|
forgeViewer.value.fitToView([level.dbId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return { findLevels, profile };
|
watch(
|
||||||
|
() => route,
|
||||||
|
(newValue) => {
|
||||||
|
console.log(newValue);
|
||||||
|
newValue && showLevels();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return { findLevels, showLevels, updateViewerFloor };
|
||||||
}
|
}
|
||||||
|
|
||||||
export default useForgeFloor;
|
export default useForgeFloor;
|
||||||
|
@ -1,49 +1,141 @@
|
|||||||
import { watch, inject, markRaw, ref } from "vue";
|
import { watch, inject, markRaw, ref, computed, onMounted } from "vue";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import useHeatmapBarStore from "@/stores/useHeatmapBarStore";
|
||||||
|
import useSystemShowData from "@/hooks/useSystemShowData";
|
||||||
|
|
||||||
export default function useForgeHeatmap(dataVizExtn, forgeViewer){
|
export default function useForgeHeatmap() {
|
||||||
const { subscribeData } = inject("system_deviceList");
|
const route = useRoute();
|
||||||
|
const { subscribeData, realtimeData } = inject("system_deviceList");
|
||||||
|
|
||||||
const createHeatMap = async (heatMapName) => {
|
const store = useHeatmapBarStore();
|
||||||
|
|
||||||
|
const forgeViewer = ref(null);
|
||||||
|
const dataVizExtn = ref(null);
|
||||||
|
const updateViewExtension = (viewer, dataVisualization) => {
|
||||||
|
forgeViewer.value = viewer;
|
||||||
|
dataVizExtn.value = dataVisualization;
|
||||||
|
};
|
||||||
|
|
||||||
|
//create the heatmap
|
||||||
|
function getSensorValue(device, sensorType, pointData) {
|
||||||
|
const dev = realtimeData.value.find(
|
||||||
|
({ device_number }) => device_number === device.id
|
||||||
|
);
|
||||||
|
if (dev) {
|
||||||
|
const [min, max] = store.heatmapConfig?.range;
|
||||||
|
const point = dev.data.find(({ point }) => point === route.query?.gas);
|
||||||
|
console.log(9, device, dev, point, (point?.value - min || 0) / max);
|
||||||
|
|
||||||
|
return Math.random();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { flatSubData } = useSystemShowData();
|
||||||
|
|
||||||
|
const data = computed(() =>
|
||||||
|
flatSubData.value?.map((d) => ({
|
||||||
|
...d,
|
||||||
|
...Object.fromEntries(
|
||||||
|
d.points.map(({ point, value }) => [point, 0]) || []
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => realtimeData,
|
||||||
|
() => {
|
||||||
|
dataVizExtn.value &&
|
||||||
|
Object.keys(dataVizExtn.value?.surfaceShading)?.length &&
|
||||||
|
dataVizExtn.value.updateSurfaceShading(getSensorValue);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const createHeatMap = async () => {
|
||||||
|
if (!dataVizExtn.value) return;
|
||||||
|
const heatMapName = `iot_heatmap_${route.query?.gas}`;
|
||||||
|
console.log("createHeatMap", heatMapName);
|
||||||
const {
|
const {
|
||||||
SurfaceShadingData,
|
SurfaceShadingData,
|
||||||
SurfaceShadingPoint,
|
SurfaceShadingPoint,
|
||||||
SurfaceShadingNode,
|
SurfaceShadingNode,
|
||||||
SurfaceShadingGroup,
|
SurfaceShadingGroup,
|
||||||
} = Autodesk.DataVisualization.Core;
|
} = Autodesk.DataVisualization.Core;
|
||||||
const shadingGroup = new SurfaceShadingGroup(`iot_heatmap_${heatMapName}`);
|
const shadingGroup = new SurfaceShadingGroup(`${heatMapName}`);
|
||||||
const rooms = new Map();
|
const rooms = new Map();
|
||||||
|
|
||||||
for (const { id, roomDbId, position, sensorTypes } of subscribeData.value) {
|
const roomSet = new Set(data.value.map(({ room_dbid }) => room_dbid));
|
||||||
if (!id || roomDbId == -1 || !roomDbId) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rooms.has(roomDbId)) {
|
// 每個room是一個node
|
||||||
const room = new SurfaceShadingNode(id, roomDbId);
|
[...roomSet].forEach((roomDbId) => {
|
||||||
shadingGroup.addChild(room);
|
if (!roomDbId) {
|
||||||
rooms.set(roomDbId, room);
|
return;
|
||||||
}
|
}
|
||||||
const room = rooms.get(roomDbId);
|
const room = new SurfaceShadingNode(`room_${roomDbId}`, roomDbId);
|
||||||
room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes));
|
|
||||||
}
|
|
||||||
|
|
||||||
const shadingData = new SurfaceShadingData();
|
//相同room內的設備
|
||||||
|
data.value
|
||||||
|
.filter(({ room_dbid }) => room_dbid === roomDbId)
|
||||||
|
.forEach(
|
||||||
|
({
|
||||||
|
device_number: id,
|
||||||
|
device_coordinate_3d: position,
|
||||||
|
sensorTypes,
|
||||||
|
}) =>
|
||||||
|
room.addPoint(new SurfaceShadingPoint(id, position, sensorTypes))
|
||||||
|
);
|
||||||
|
|
||||||
|
shadingGroup.addChild(room);
|
||||||
|
});
|
||||||
|
|
||||||
|
// data.value.forEach(
|
||||||
|
// ({
|
||||||
|
// device_number: id,
|
||||||
|
// room_dbid: roomDbId,
|
||||||
|
// device_coordinate_3d: position,
|
||||||
|
// sensorTypes,
|
||||||
|
// }) => {
|
||||||
|
// if (!id || roomDbId == -1 || !roomDbId) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (!rooms.has(roomDbId)) {
|
||||||
|
// const room = new SurfaceShadingNode(id, roomDbId);
|
||||||
|
// shadingGroup.addChild(room);
|
||||||
|
// rooms.set(roomDbId, room);
|
||||||
|
// }
|
||||||
|
// const room = rooms.get(roomDbId);
|
||||||
|
// room.addPoint(new SurfaceShadingPoint(id, position, route.query.gas));
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
const shadingData = new SurfaceShadingData(`${heatMapName}`);
|
||||||
shadingData.addChild(shadingGroup);
|
shadingData.addChild(shadingGroup);
|
||||||
shadingData.initialize(forgeViewer.value?.model);
|
shadingData.initialize(forgeViewer.value?.model);
|
||||||
|
|
||||||
await dataVizExtn.value.setupSurfaceShading(
|
await dataVizExtn.value.setupSurfaceShading(
|
||||||
forgeViewer.value.model,
|
forgeViewer.value.model,
|
||||||
shadingData
|
shadingData
|
||||||
);
|
);
|
||||||
dataVizExtn.value.registerSurfaceShadingColors(
|
dataVizExtn.value.registerSurfaceShadingColors(
|
||||||
heatMapName,
|
route.query?.gas,
|
||||||
[0x0000ff, 0x00ff00, 0xffff00, 0xff0000]
|
store.heatmapConfig?.color
|
||||||
);
|
);
|
||||||
dataVizExtn.value.renderSurfaceShading(
|
dataVizExtn.value.renderSurfaceShading(
|
||||||
`iot_heatmap_${heatMapName}`,
|
|
||||||
heatMapName,
|
heatMapName,
|
||||||
|
route.query?.gas,
|
||||||
getSensorValue
|
getSensorValue
|
||||||
);
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
watch(
|
||||||
|
data,
|
||||||
|
(newValue, oldValue) => {
|
||||||
|
dataVizExtn.value?.removeSurfaceShading();
|
||||||
|
createHeatMap(route.query.gas);
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
return { createHeatMap, updateViewExtension };
|
||||||
|
}
|
||||||
|
@ -1,17 +1,21 @@
|
|||||||
import { watch, inject, markRaw, ref, computed } from "vue";
|
import { watch, inject, markRaw, ref, computed, provide } from "vue";
|
||||||
import useAlarmStore from "@/stores/useAlarmStore";
|
import useAlarmStore from "@/stores/useAlarmStore";
|
||||||
import hexToRgb from "@/util/hexToRgb";
|
import hexToRgb from "@/util/hexToRgb";
|
||||||
import { useRoute } from "vue-router";
|
import useSystemShowData from "@/hooks/useSystemShowData"
|
||||||
import useSelectedFloor from "@/hooks/useSelectedFloor";
|
import useForgeHeatmap from "./useForgeHeatmap";
|
||||||
|
import useForgeFloor from "./useForgeFloor";
|
||||||
|
|
||||||
export default function useForgeSprite() {
|
export default function useForgeSprite() {
|
||||||
const store = useAlarmStore();
|
|
||||||
const { subscribeData } = inject("system_deviceList");
|
const { subscribeData } = inject("system_deviceList");
|
||||||
const { getCurrentInfoModalData, clearSelectedDeviceInfo } = inject(
|
const { getCurrentInfoModalData, clearSelectedDeviceInfo } = inject(
|
||||||
"system_selectedDevice"
|
"system_selectedDevice"
|
||||||
);
|
);
|
||||||
const forgeViewer = ref(null);
|
const forgeViewer = ref(null);
|
||||||
const dataVizExtn = ref(null);
|
const dataVizExtn = ref(null);
|
||||||
|
|
||||||
|
const { createHeatMap, updateViewExtension } = useForgeHeatmap();
|
||||||
|
const { updateViewerFloor } = useForgeFloor();
|
||||||
|
|
||||||
const updateDataVisualization = async (viewer) => {
|
const updateDataVisualization = async (viewer) => {
|
||||||
if (!forgeViewer.value) {
|
if (!forgeViewer.value) {
|
||||||
forgeViewer.value = markRaw(viewer);
|
forgeViewer.value = markRaw(viewer);
|
||||||
@ -21,6 +25,8 @@ export default function useForgeSprite() {
|
|||||||
"Autodesk.DataVisualization"
|
"Autodesk.DataVisualization"
|
||||||
);
|
);
|
||||||
dataVizExtn.value = markRaw(dataVisualization);
|
dataVizExtn.value = markRaw(dataVisualization);
|
||||||
|
updateViewExtension(markRaw(viewer), markRaw(dataVisualization));
|
||||||
|
updateViewerFloor(markRaw(viewer), markRaw(dataVisualization))
|
||||||
};
|
};
|
||||||
|
|
||||||
function onSpriteClicked(event) {
|
function onSpriteClicked(event) {
|
||||||
@ -45,14 +51,7 @@ export default function useForgeSprite() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { selectedFloor } = useSelectedFloor();
|
const { flatSubData } = useSystemShowData()
|
||||||
const showData = computed(() =>
|
|
||||||
selectedFloor.value?.key === "main"
|
|
||||||
? subscribeData.value
|
|
||||||
: subscribeData.value.filter(
|
|
||||||
({ floor_guid }) => floor_guid === selectedFloor.value?.key
|
|
||||||
) || []
|
|
||||||
);
|
|
||||||
|
|
||||||
// 創建 sprites
|
// 創建 sprites
|
||||||
const createSprites = async () => {
|
const createSprites = async () => {
|
||||||
@ -70,9 +69,8 @@ export default function useForgeSprite() {
|
|||||||
);
|
);
|
||||||
const viewableData = new DataVizCore.ViewableData();
|
const viewableData = new DataVizCore.ViewableData();
|
||||||
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
|
viewableData.spriteSize = 24; // Sprites as points of size 24 x 24 pixels
|
||||||
showData.value?.forEach((d, index) => {
|
flatSubData.value?.forEach((d, index) => {
|
||||||
if (d.device_coordinate_3d) {
|
if (d.device_coordinate_3d) {
|
||||||
console.log(d.device_coordinate_3d);
|
|
||||||
const position = d.device_coordinate_3d;
|
const position = d.device_coordinate_3d;
|
||||||
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
|
style.color = new THREE.Color(hexToRgb(d.device_normal_color));
|
||||||
const viewable = new DataVizCore.SpriteViewable(
|
const viewable = new DataVizCore.SpriteViewable(
|
||||||
@ -89,6 +87,7 @@ export default function useForgeSprite() {
|
|||||||
viewableData.finish().then(
|
viewableData.finish().then(
|
||||||
() => {
|
() => {
|
||||||
dataVizExtn.value.addViewables(viewableData);
|
dataVizExtn.value.addViewables(viewableData);
|
||||||
|
createHeatMap();
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -98,9 +97,12 @@ export default function useForgeSprite() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => showData,
|
() => flatSubData,
|
||||||
() => {
|
() => {
|
||||||
forgeViewer.value?.isLoadDone() && createSprites();
|
if (forgeViewer.value?.isLoadDone()) {
|
||||||
|
createSprites();
|
||||||
|
showSubSystemObjects();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true,
|
deep: true,
|
||||||
@ -146,7 +148,10 @@ export default function useForgeSprite() {
|
|||||||
for (var i = 0; i < allDbIdsStr.length; i++) {
|
for (var i = 0; i < allDbIdsStr.length; i++) {
|
||||||
forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
|
forgeViewer.value.hide(parseInt(allDbIdsStr[i]));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const showSubSystemObjects = () => {
|
||||||
|
hideAllObjects();
|
||||||
subscribeData.value.forEach((value, index) => {
|
subscribeData.value.forEach((value, index) => {
|
||||||
forgeViewer.value.show(value.forge_dbid);
|
forgeViewer.value.show(value.forge_dbid);
|
||||||
});
|
});
|
||||||
@ -166,11 +171,13 @@ export default function useForgeSprite() {
|
|||||||
forgeViewer.value.tearDown();
|
forgeViewer.value.tearDown();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createSprites,
|
createSprites,
|
||||||
updateDataVisualization,
|
updateDataVisualization,
|
||||||
hideAllObjects,
|
showSubSystemObjects,
|
||||||
forgeClickListener,
|
forgeClickListener,
|
||||||
clear
|
clear,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
27
src/hooks/useSystemShowData.js
Normal file
27
src/hooks/useSystemShowData.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import useSelectedFloor from "@/hooks/useSelectedFloor";
|
||||||
|
import { computed, inject, watch } from "vue";
|
||||||
|
|
||||||
|
function useSystemShowData() {
|
||||||
|
const { data } = inject("system_deviceList");
|
||||||
|
const { selectedFloor } = useSelectedFloor();
|
||||||
|
|
||||||
|
const showData = computed(() =>
|
||||||
|
selectedFloor.value?.key === "main"
|
||||||
|
? data.value
|
||||||
|
: data.value.filter(
|
||||||
|
({ floor_guid }) => floor_guid === selectedFloor.value?.key
|
||||||
|
) || []
|
||||||
|
);
|
||||||
|
|
||||||
|
const flatSubData = computed(() => {
|
||||||
|
let items = [];
|
||||||
|
showData.value.forEach((device) => {
|
||||||
|
items = [...items, ...device.device_list];
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { showData, flatSubData };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useSystemShowData;
|
31
src/stores/useHeatmapBarStore.js
Normal file
31
src/stores/useHeatmapBarStore.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import axios from "axios";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
import { computed, ref, onMounted } from "vue";
|
||||||
|
|
||||||
|
const useHeatmapBarStore = defineStore("heatmap", () => {
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const allHeatMaps = ref({});
|
||||||
|
const heatmapConfig = computed(() => allHeatMaps.value[route.query?.gas]);
|
||||||
|
|
||||||
|
const getConfig = async () => {
|
||||||
|
const api =
|
||||||
|
import.meta.env.MODE === "production"
|
||||||
|
? "/dist/config.json"
|
||||||
|
: "/config.json";
|
||||||
|
const res = await axios.get(api);
|
||||||
|
console.log(res);
|
||||||
|
allHeatMaps.value = res.data.heatmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getConfig();
|
||||||
|
});
|
||||||
|
|
||||||
|
const heat_bar_isShow = computed(() => Boolean(heatmapConfig.value));
|
||||||
|
|
||||||
|
return { heatmapConfig, heat_bar_isShow };
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useHeatmapBarStore;
|
@ -102,7 +102,7 @@ const closeModal = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
|
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -194,9 +194,10 @@ const openCompanyAddModal = () => {
|
|||||||
<OperationTableModal type="asset" />
|
<OperationTableModal type="asset" />
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-success btn-sm ml-2 mt-7"
|
class="btn btn-add ml-2 mt-7"
|
||||||
@click="openCompanyAddModal"
|
@click="openCompanyAddModal"
|
||||||
>
|
>
|
||||||
|
<font-awesome-icon :icon="['fas', 'plus']" />
|
||||||
{{ $t("button.add") }}
|
{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -192,9 +192,10 @@ const deleteItem = (value) => {
|
|||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm btn-success"
|
class="btn btn-sm btn-add"
|
||||||
@click.stop.prevent="openModal"
|
@click.stop.prevent="openModal"
|
||||||
>
|
>
|
||||||
|
<font-awesome-icon :icon="['fas', 'plus']" />
|
||||||
{{ $t("assetManagement.add_sensor") }}
|
{{ $t("assetManagement.add_sensor") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -142,13 +142,6 @@ const removeAccount = async (id) => {
|
|||||||
<AccountPasswordModal :reset="resetModalForm" :account="formState" />
|
<AccountPasswordModal :reset="resetModalForm" :account="formState" />
|
||||||
<Table :columns="columns" :dataSource="dataSource" :loading="loading">
|
<Table :columns="columns" :dataSource="dataSource" :loading="loading">
|
||||||
<template #beforeTable>
|
<template #beforeTable>
|
||||||
<button
|
|
||||||
class="btn btn-success mr-3"
|
|
||||||
@click.stop.prevent="() => openModal(null)"
|
|
||||||
>
|
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />
|
|
||||||
{{ $t("button.add") }}
|
|
||||||
</button>
|
|
||||||
<div class="flex items-center mb-8">
|
<div class="flex items-center mb-8">
|
||||||
<Input
|
<Input
|
||||||
:placeholder="t('accountManagement.name_placeholder')"
|
:placeholder="t('accountManagement.name_placeholder')"
|
||||||
@ -161,18 +154,21 @@ const removeAccount = async (id) => {
|
|||||||
name="Role_full_name"
|
name="Role_full_name"
|
||||||
:value="searchData"
|
:value="searchData"
|
||||||
/>
|
/>
|
||||||
<button
|
<button class="btn btn-search ml-5" @click.stop.prevent="onSearch">
|
||||||
class="btn btn-outline-success ml-5"
|
<font-awesome-icon :icon="['fas', 'search']" />
|
||||||
@click.stop.prevent="onSearch"
|
|
||||||
>
|
|
||||||
{{ $t("button.search") }}
|
{{ $t("button.search") }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button class="btn btn-neutral mx-4" @click.stop.prevent="onReset">
|
||||||
class="btn btn-outline-success mx-4"
|
|
||||||
@click.stop.prevent="onReset"
|
|
||||||
>
|
|
||||||
{{ $t("button.reset") }}
|
{{ $t("button.reset") }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="btn btn-add ml-10"
|
||||||
|
@click.stop.prevent="() => openModal(null)"
|
||||||
|
>
|
||||||
|
<font-awesome-icon :icon="['fas', 'plus']" />
|
||||||
|
{{ $t("button.add") }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #bodyCell="{ record, column, index }">
|
<template #bodyCell="{ record, column, index }">
|
||||||
|
@ -102,13 +102,11 @@ const onSearch = () => {
|
|||||||
name="Full_name"
|
name="Full_name"
|
||||||
:value="searchRole"
|
:value="searchRole"
|
||||||
/>
|
/>
|
||||||
<button
|
<button class="btn btn-search mx-3" @click.stop.prevent="onSearch">
|
||||||
class="btn btn-outline-info mx-3"
|
<font-awesome-icon :icon="['fas', 'search']" />
|
||||||
@click.stop.prevent="onSearch"
|
|
||||||
>
|
|
||||||
{{ $t("button.search") }}
|
{{ $t("button.search") }}
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-success ml-10" @click.stop.prevent="add">
|
<button class="btn btn-add ml-10" @click.stop.prevent="add">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" /> {{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" /> {{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,10 @@ const { search } = inject("alert_table");
|
|||||||
<AlertSearchNormalBtns />
|
<AlertSearchNormalBtns />
|
||||||
<AlertSearchAckBtns />
|
<AlertSearchAckBtns />
|
||||||
<AlertSearchTimeRange />
|
<AlertSearchTimeRange />
|
||||||
<button class="btn btn-success ml-8" @click.stop.prevent="search">{{ $t("button.query")}}</button>
|
<button class="btn btn-search ml-8" @click.stop.prevent="search">
|
||||||
|
<font-awesome-icon :icon="['fas', 'search']" class=" text-lg" />
|
||||||
|
{{ $t("button.search")}}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full flex flex-wrap items-center justify-start">
|
<div class="w-full flex flex-wrap items-center justify-start">
|
||||||
<AlertSearchTypesButton />
|
<AlertSearchTypesButton />
|
||||||
|
@ -88,7 +88,7 @@ const closeModal = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
|
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -127,7 +127,7 @@ const closeModal = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button class="btn btn-sm btn-success mr-3" @click.stop.prevent="openModal">
|
<button class="btn btn-sm btn-add mr-3" @click.stop.prevent="openModal">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
|
import { twMerge } from "tailwind-merge";
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// 假資料
|
// 假資料
|
||||||
const mockData = ref([
|
const mockData = ref([
|
||||||
@ -33,42 +34,42 @@ const mockData = ref([
|
|||||||
sub_system_tag: "ECP3",
|
sub_system_tag: "ECP3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Elevator system",
|
title: "Elevator System",
|
||||||
icon: "building",
|
icon: "building",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "High voltage switchboard",
|
title: "High Voltage Switchboard",
|
||||||
icon: "charging-station",
|
icon: "charging-station",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Low voltage switchboard",
|
title: "Low Voltage Switchboard",
|
||||||
icon: "charging-station",
|
icon: "charging-station",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Water supply system",
|
title: "Water Supply System",
|
||||||
icon: "tint",
|
icon: "tint",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Sewage and wastewater equipment",
|
title: "Sewage And Wastewater Equipment",
|
||||||
icon: "water",
|
icon: "water",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Emergency generator",
|
title: "Emergency Generator",
|
||||||
icon: "car-battery",
|
icon: "car-battery",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
@ -82,35 +83,35 @@ const mockData = ref([
|
|||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "CCTV system",
|
title: "CCTV System",
|
||||||
icon: "video",
|
icon: "video",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Access control system",
|
title: "Access Control System",
|
||||||
icon: "door-open",
|
icon: "door-open",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Shutdown system",
|
title: "Shutdown System",
|
||||||
icon: "car",
|
icon: "car",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Emergency rescue system",
|
title: "Emergency Rescue System",
|
||||||
icon: "exclamation-triangle",
|
icon: "exclamation-triangle",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
sub_system_tag: null,
|
sub_system_tag: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Air supply and exhaust system",
|
title: "Air Supply Aand Exhaust System",
|
||||||
icon: "wind",
|
icon: "wind",
|
||||||
isError: false,
|
isError: false,
|
||||||
main_system_tag: null,
|
main_system_tag: null,
|
||||||
@ -124,7 +125,7 @@ const navigateToSubSystem = (mainSystemId, subSystemId) => {
|
|||||||
params: {
|
params: {
|
||||||
main_system_id: mainSystemId,
|
main_system_id: mainSystemId,
|
||||||
sub_system_id: subSystemId,
|
sub_system_id: subSystemId,
|
||||||
floor_id: 'main'
|
floor_id: "main",
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -135,10 +136,14 @@ const navigateToSubSystem = (mainSystemId, subSystemId) => {
|
|||||||
<div
|
<div
|
||||||
v-for="(item, index) in mockData"
|
v-for="(item, index) in mockData"
|
||||||
:key="index"
|
:key="index"
|
||||||
:class="[
|
:class="
|
||||||
'w-full sm:w-1/2 lg:w-1/4 relative my-2 cursor-pointer',
|
twMerge(
|
||||||
item.sub_system_tag ? '' : 'grayscale opacity-70 cursor-not-allowed'
|
'w-full sm:w-1/2 lg:w-1/4 relative my-2 ',
|
||||||
]"
|
item.sub_system_tag
|
||||||
|
? 'saturate-200 cursor-pointer text-base text-info'
|
||||||
|
: 'grayscale opacity-70 cursor-not-allowed text-sm'
|
||||||
|
)
|
||||||
|
"
|
||||||
@click="navigateToSubSystem(item.main_system_tag, item.sub_system_tag)"
|
@click="navigateToSubSystem(item.main_system_tag, item.sub_system_tag)"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@ -155,7 +160,9 @@ const navigateToSubSystem = (mainSystemId, subSystemId) => {
|
|||||||
></FontAwesomeIcon>
|
></FontAwesomeIcon>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon-text">
|
<div class="icon-text">
|
||||||
<div class="text-slate-300 text-sm">{{ item.title }}</div>
|
<div class="">
|
||||||
|
{{ item.title }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,6 +8,8 @@ import {
|
|||||||
addGraphTableDataWithoutSubSys,
|
addGraphTableDataWithoutSubSys,
|
||||||
editGraphTableDataWithoutSubSys,
|
editGraphTableDataWithoutSubSys,
|
||||||
} from "@/apis/graph";
|
} from "@/apis/graph";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
const { t } = useI18n();
|
||||||
const BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
const BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -121,10 +123,10 @@ watch(
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button class="btn btn-success mr-3" @click.stop.prevent="openModal">
|
<button class="btn btn-add mr-3" @click.stop.prevent="openModal">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
<Modal id="graph_add_item" title="圖資上傳" :onCancel="onCancel" width="800">
|
<Modal id="graph_add_item" :title="t('graphManagement.upload')" :onCancel="onCancel" width="800">
|
||||||
<template #modalContent>
|
<template #modalContent>
|
||||||
<form ref="form" class="mt-5">
|
<form ref="form" class="mt-5">
|
||||||
<div class="mb-2">
|
<div class="mb-2">
|
||||||
|
@ -76,15 +76,19 @@ const isSearchButtonDisabled = computed(() => {
|
|||||||
|
|
||||||
const submitBtns = computed(() => [
|
const submitBtns = computed(() => [
|
||||||
{
|
{
|
||||||
title: t("button.query"),
|
title: t("button.search"),
|
||||||
key: "submit",
|
key: "submit",
|
||||||
active: false,
|
active: false,
|
||||||
onClick: submit,
|
onClick: submit,
|
||||||
|
icon: "search",
|
||||||
|
btn: "btn-search",
|
||||||
disabled: isSearchButtonDisabled.value,
|
disabled: isSearchButtonDisabled.value,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("button.export"),
|
title: t("button.export"),
|
||||||
key: "export",
|
key: "export",
|
||||||
|
icon: "download",
|
||||||
|
btn: "btn-export",
|
||||||
active: false,
|
active: false,
|
||||||
onClick: (e) => submit(e, "export"),
|
onClick: (e) => submit(e, "export"),
|
||||||
disabled: isSearchButtonDisabled.value,
|
disabled: isSearchButtonDisabled.value,
|
||||||
@ -120,7 +124,7 @@ watch(
|
|||||||
status="info"
|
status="info"
|
||||||
:cancel="cancelToastOpen"
|
:cancel="cancelToastOpen"
|
||||||
/>
|
/>
|
||||||
<ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" />
|
<ButtonGroup class="ml-5" :items="submitBtns" :withLine="false" :withBtnClass="true"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
@ -29,14 +29,14 @@ const initializeItems = () => {
|
|||||||
: true,
|
: true,
|
||||||
Type: 1,
|
Type: 1,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: t("history.time_range"),
|
// title: t("history.time_range"),
|
||||||
key: "startMonthTime",
|
// key: "startMonthTime",
|
||||||
active: searchParams.value.Type
|
// active: searchParams.value.Type
|
||||||
? parseInt(searchParams.value.Type) === 2
|
// ? parseInt(searchParams.value.Type) === 2
|
||||||
: false,
|
// : false,
|
||||||
Type: 2,
|
// Type: 2,
|
||||||
},
|
// },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
itemsForStartTime.value = [
|
itemsForStartTime.value = [
|
||||||
|
@ -10,6 +10,8 @@ const { searchParams, changeParams } = useSearchParam();
|
|||||||
|
|
||||||
const selectedBuilding = ref([]);
|
const selectedBuilding = ref([]);
|
||||||
const deviceData = ref([]);
|
const deviceData = ref([]);
|
||||||
|
const searchTerm = ref(""); //搜尋文字
|
||||||
|
const activeSearchTerm = ref("");
|
||||||
|
|
||||||
const getDeviceData = async (sub_tag, renew) => {
|
const getDeviceData = async (sub_tag, renew) => {
|
||||||
const res = await getHistorySideBar(sub_tag);
|
const res = await getHistorySideBar(sub_tag);
|
||||||
@ -162,6 +164,28 @@ const changeSelected = (Device_list, renew = false) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filteredDeviceData = computed(() => {
|
||||||
|
if (!activeSearchTerm.value) return deviceData.value;
|
||||||
|
return deviceData.value.map((building) => ({
|
||||||
|
...building,
|
||||||
|
floors: building.floors.map((floor) => ({
|
||||||
|
...floor,
|
||||||
|
devices: floor.devices.filter((device) =>
|
||||||
|
device.device_name.includes(activeSearchTerm.value)
|
||||||
|
),
|
||||||
|
})).filter(floor => floor.devices.length > 0)
|
||||||
|
})).filter(building => building.floors.length > 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSearch = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
activeSearchTerm.value = searchTerm.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = (e) => {
|
||||||
|
searchTerm.value = e.target.value;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -175,12 +199,15 @@ const changeSelected = (Device_list, renew = false) => {
|
|||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
|
:value="searchTerm"
|
||||||
|
@input="handleInput"
|
||||||
:placeholder="t('button.enter_text')"
|
:placeholder="t('button.enter_text')"
|
||||||
class="text-white bg-transparent w-full"
|
class="text-white bg-transparent w-full"
|
||||||
|
@keyup.enter="handleSearch"
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<ul class="menu text-lg">
|
<ul class="menu text-lg">
|
||||||
<template v-for="building in deviceData" :key="building.building_tag">
|
<template v-for="building in filteredDeviceData" :key="building.building_tag">
|
||||||
<li>
|
<li>
|
||||||
<details :open="selectedBuilding.includes(building.building_tag)">
|
<details :open="selectedBuilding.includes(building.building_tag)">
|
||||||
<summary>
|
<summary>
|
||||||
|
@ -29,8 +29,10 @@ const exportFile = async () => {
|
|||||||
|
|
||||||
const submitBtns = computed(() => [
|
const submitBtns = computed(() => [
|
||||||
{
|
{
|
||||||
title: t("button.query"),
|
title: t("button.search"),
|
||||||
key: "submit",
|
key: "submit",
|
||||||
|
icon: "search",
|
||||||
|
btn: "btn-search",
|
||||||
active: false,
|
active: false,
|
||||||
onClick: search,
|
onClick: search,
|
||||||
disabled: isSearchDisabled.value,
|
disabled: isSearchDisabled.value,
|
||||||
@ -38,6 +40,8 @@ const submitBtns = computed(() => [
|
|||||||
{
|
{
|
||||||
title: t("button.export"),
|
title: t("button.export"),
|
||||||
key: "export",
|
key: "export",
|
||||||
|
icon: "download",
|
||||||
|
btn: "btn-export",
|
||||||
active: false,
|
active: false,
|
||||||
onClick: exportFile,
|
onClick: exportFile,
|
||||||
disabled: isSearchDisabled.value,
|
disabled: isSearchDisabled.value,
|
||||||
@ -84,10 +88,11 @@ watch(
|
|||||||
<ButtonGroup
|
<ButtonGroup
|
||||||
:items="submitBtns"
|
:items="submitBtns"
|
||||||
:withLine="false"
|
:withLine="false"
|
||||||
|
:withBtnClass="true"
|
||||||
class="ml-5 mr-8 xl:mr-10"
|
class="ml-5 mr-8 xl:mr-10"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<button class="btn btn-info" @click.stop.prevent="() => openModal()">
|
<button class="btn btn-add" @click.stop.prevent="() => openModal()">
|
||||||
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
<font-awesome-icon :icon="['fas', 'plus']" />{{ $t("button.add") }}
|
||||||
</button>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
|
@ -38,7 +38,7 @@ const setButtonItems = () => {
|
|||||||
params: ["work_type", "sub_system_tag"],
|
params: ["work_type", "sub_system_tag"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('operation.maintainance'),
|
title: t('operation.maintenance'),
|
||||||
key: "maintain",
|
key: "maintain",
|
||||||
active: searchParams.value.work_type === "1",
|
active: searchParams.value.work_type === "1",
|
||||||
work_type: 1,
|
work_type: 1,
|
||||||
|
@ -229,7 +229,7 @@ watch(
|
|||||||
"work_type"
|
"work_type"
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
const work_types = [t("operation.maintainance"), t("operation.repair")];
|
const work_types = [t("operation.maintenance"), t("operation.repair")];
|
||||||
formState.value[searchParams.value?.work_type - 1].work_type =
|
formState.value[searchParams.value?.work_type - 1].work_type =
|
||||||
searchParams.value.work_type;
|
searchParams.value.work_type;
|
||||||
formState.value[searchParams.value?.work_type - 1].work_type_name =
|
formState.value[searchParams.value?.work_type - 1].work_type_name =
|
||||||
|
@ -56,12 +56,11 @@ const getData = async () => {
|
|||||||
building_tag: buildingStore.selectedBuilding?.building_tag,
|
building_tag: buildingStore.selectedBuilding?.building_tag,
|
||||||
})
|
})
|
||||||
const devices = res.data.map(d => ({
|
const devices = res.data.map(d => ({
|
||||||
...d, key: d.full_name, device_list: d.device_list.map((dev, index) => ({
|
...d, key: d.full_name, device_list: d.device_list.filter(({ device_coordinate_3d }) => device_coordinate_3d).map((dev, index) => ({
|
||||||
...dev,
|
...dev,
|
||||||
forge_dbid: parseInt(dev.forge_dbid),
|
forge_dbid: parseInt(dev.forge_dbid),
|
||||||
device_coordinate_3d: dev.device_coordinate_3d
|
room_dbid: parseInt(dev.room_dbid),
|
||||||
? JSON.parse(dev.device_coordinate_3d)
|
device_coordinate_3d: JSON.parse(dev.device_coordinate_3d),
|
||||||
: null,
|
|
||||||
alarmMsg: "",
|
alarmMsg: "",
|
||||||
is_show: true,
|
is_show: true,
|
||||||
currentColor: dev.device_normal_point_color,
|
currentColor: dev.device_normal_point_color,
|
||||||
@ -195,9 +194,7 @@ const getCurrentInfoModalData = async (e, position, value) => {
|
|||||||
}
|
}
|
||||||
const mobile = isMobile(e);
|
const mobile = isMobile(e);
|
||||||
selectedDevice.value = {
|
selectedDevice.value = {
|
||||||
initPos: mobile
|
initPos: { left: `50%`, top: `50%` },
|
||||||
? { left: `50%`, top: `50%` }
|
|
||||||
: { left: `${position.left}px`, top: `${position.top}px` },
|
|
||||||
value,
|
value,
|
||||||
isMobile: mobile,
|
isMobile: mobile,
|
||||||
};
|
};
|
||||||
@ -207,7 +204,7 @@ const getCurrentInfoModalData = async (e, position, value) => {
|
|||||||
const selectedDeviceRealtime = computed(() => realtimeData.value?.find(({ device_number }) => device_number === selectedDevice.value?.value?.device_number)?.data)
|
const selectedDeviceRealtime = computed(() => realtimeData.value?.find(({ device_number }) => device_number === selectedDevice.value?.value?.device_number)?.data)
|
||||||
|
|
||||||
const clearSelectedDeviceInfo = () => {
|
const clearSelectedDeviceInfo = () => {
|
||||||
|
|
||||||
selectedDevice.value.value = null;
|
selectedDevice.value.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed, inject, watch } from "vue"
|
import { computed, inject, watch } from "vue"
|
||||||
import useSelectedFloor from "@/hooks/useSelectedFloor"
|
import useSystemShowData from "@/hooks/useSystemShowData"
|
||||||
|
|
||||||
const { data } = inject("system_deviceList")
|
|
||||||
|
|
||||||
const { getCurrentInfoModalData } = inject("system_selectedDevice")
|
const { getCurrentInfoModalData } = inject("system_selectedDevice")
|
||||||
|
|
||||||
const { selectedFloor } = useSelectedFloor()
|
const { showData } = useSystemShowData()
|
||||||
|
|
||||||
const showData = computed(() => selectedFloor.value?.key === 'main' ? data.value : data.value.filter(({ floor_guid }) => floor_guid === selectedFloor.value?.key) || [])
|
|
||||||
|
|
||||||
watch(selectedFloor, (newValue) => {
|
|
||||||
console.log(newValue)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
const fitToView = (forge_dbid) => {
|
||||||
|
// console.log(forge_dbid)
|
||||||
|
// window.NOP_VIEWER.hide(forge_dbid + 3);
|
||||||
|
// window.NOP_VIEWER.impl.invalidate(true);
|
||||||
|
window.NOP_VIEWER.fitToView([forge_dbid])
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -39,7 +38,7 @@ watch(selectedFloor, (newValue) => {
|
|||||||
<span>{{ device.device_status }}</span>
|
<span>{{ device.device_status }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-text border-0 "
|
<button class="btn-text border-0 "
|
||||||
@click.stop.prevent="(e) => getCurrentInfoModalData(e, { left: e.clientX, top: e.clientY }, device)">{{
|
@click.prevent="(e) => getCurrentInfoModalData(e, { left: e.clientX, top: e.clientY }, device)">{{
|
||||||
$t("system.details") }}</button>
|
$t("system.details") }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -39,7 +39,7 @@ const onClick = (item) => {
|
|||||||
router.push({
|
router.push({
|
||||||
name: 'sub_system', params: {
|
name: 'sub_system', params: {
|
||||||
...route.params, floor_id: item.key
|
...route.params, floor_id: item.key
|
||||||
}, query: { ...route.query, gas: route.query.gas }
|
}, query: { ...route.query, gas: route.query.gas, mode: route.params.floor_id === "main" ? "3D" : route.query.mode }
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal id="system_info_modal" :onCancel="onCancel" width="600" :draggable="!data?.isMobile" :backdrop="false"
|
<Modal id="system_info_modal" :onCancel="onCancel" width="600" :draggable="!data?.isMobile" :backdrop="false"
|
||||||
:modalStyle="position" :class="data?.isMobile ? '-translate-x-1/2 -translate-y-1/2' : ''">
|
:modalStyle="position" class="-translate-x-1/2 -translate-y-1/2">
|
||||||
<template #modalContent>
|
<template #modalContent>
|
||||||
<SystemInfoModalContent />
|
<SystemInfoModalContent />
|
||||||
</template>
|
</template>
|
||||||
|
Loading…
Reference in New Issue
Block a user