Merge branch 'feature/system'

This commit is contained in:
koko 2024-10-28 15:08:31 +08:00
commit 9f09bd1b2c
10 changed files with 373 additions and 139 deletions

44
public/config.json Normal file
View 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³"
}
}
}

View File

@ -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>

View File

@ -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;

View File

@ -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 };
}

View File

@ -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) {
@ -35,7 +41,6 @@ export default function useForgeSprite() {
console.log("onSpriteClicked", event.target); console.log("onSpriteClicked", event.target);
console.log("onSpriteClicked", data); console.log("onSpriteClicked", data);
// modalContent.value = data; // modalContent.value = data;
debugger;
if (data) { if (data) {
getCurrentInfoModalData( getCurrentInfoModalData(
event, event,
@ -45,14 +50,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 +68,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 +86,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 +96,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 +147,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 +170,13 @@ export default function useForgeSprite() {
forgeViewer.value.tearDown(); forgeViewer.value.tearDown();
}; };
return { return {
createSprites, createSprites,
updateDataVisualization, updateDataVisualization,
hideAllObjects, showSubSystemObjects,
forgeClickListener, forgeClickListener,
clear clear,
}; };
} }

View 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;

View 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;

View File

@ -41,12 +41,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,
@ -168,7 +167,7 @@ const getCurrentInfoModalData = (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;
} }

View File

@ -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>
@ -25,7 +24,7 @@ watch(selectedFloor, (newValue) => {
<p class="title">{{ d.full_name }}</p> <p class="title">{{ d.full_name }}</p>
<div class="grid grid-cols-3 gap-5"> <div class="grid grid-cols-3 gap-5">
<div class="col-auto relative" v-for="device in d.device_list" :key="device.device_guid"> <div class="col-auto relative" v-for="device in d.device_list" :key="device.device_guid">
<div class="item h-36"> <div class="item h-36" @click="() => fitToView(device.forge_dbid)">
<div class="left w-4/5 h-full flex flex-wrap justify-center"> <div class="left w-4/5 h-full flex flex-wrap justify-center">
<div class="sec02 w-full"> <div class="sec02 w-full">
<img v-if="device.device_image_url" :src="device.device_image_url" alt="" class="w-8 h-8"> <img v-if="device.device_image_url" :src="device.device_image_url" alt="" class="w-8 h-8">
@ -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>

View File

@ -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 }
}) })
} }