283 lines
7.3 KiB
Vue
283 lines
7.3 KiB
Vue
<script setup>
|
||
import {
|
||
ref,
|
||
onMounted,
|
||
defineProps,
|
||
computed,
|
||
onUnmounted,
|
||
watch,
|
||
watchEffect,
|
||
provide,
|
||
inject,
|
||
} from "vue";
|
||
import { getUrn, getAccessToken } from "@/apis/forge";
|
||
import { twMerge } from "tailwind-merge";
|
||
import useSystemStatusByBaja from "@/hooks/baja/useSystemStatusByBaja";
|
||
import ForgeInfoModal from "./ForgeInfoModal.vue";
|
||
import useAlarmStore from "@/stores/useAlarmStore";
|
||
const FILE_BASEURL = import.meta.env.VITE_FILE_API_BASEURL;
|
||
const { forgeLock } = inject("app_toggle");
|
||
const props = defineProps({
|
||
fullScreen: Boolean,
|
||
initialData: Object,
|
||
cubeStyle: {
|
||
type: Object,
|
||
default: {
|
||
right: 25,
|
||
top: 2,
|
||
},
|
||
},
|
||
});
|
||
|
||
const heat_bar_isShow = ref(false);
|
||
const updateHeatBarIsShow = (isShow) => {
|
||
heat_bar_isShow.value = isShow;
|
||
};
|
||
|
||
const {
|
||
subscribeData,
|
||
visibleDbid,
|
||
updateDbidPosition,
|
||
hideAllObjects,
|
||
updateForgeViewer,
|
||
forgeViewer,
|
||
urn,
|
||
loadModel,
|
||
updateInitialData,
|
||
subComponents,
|
||
} = useSystemStatusByBaja(updateHeatBarIsShow);
|
||
|
||
watch(
|
||
() => props.initialData,
|
||
(newValue) => {
|
||
newValue && updateInitialData(newValue);
|
||
},
|
||
{
|
||
deep: true,
|
||
}
|
||
);
|
||
|
||
const store = useAlarmStore();
|
||
const subscribeDataWithErrorMsg = computed(() => {
|
||
let data = { ...subscribeData.value };
|
||
|
||
for (let [key, value] of Object.entries(subscribeData.value)) {
|
||
const alarm = store.alarmData.find(
|
||
({ device_number }) => device_number === key
|
||
);
|
||
data[key].alarmMsg = alarm ? alarm.msg : "";
|
||
}
|
||
console.log("baja update data: ", data);
|
||
return data;
|
||
});
|
||
|
||
const forgeDom = ref(null);
|
||
|
||
const initViewer = (container) => {
|
||
return new Promise(function (resolve, reject) {
|
||
Autodesk.Viewing.Initializer(
|
||
{
|
||
env: "Local",
|
||
language: "en",
|
||
},
|
||
function () {
|
||
const config = {
|
||
extensions: [
|
||
"Autodesk.DataVisualization",
|
||
"Autodesk.DocumentBrowser",
|
||
],
|
||
};
|
||
let viewer = new Autodesk.Viewing.GuiViewer3D(container, config);
|
||
Autodesk.Viewing.Private.InitParametersSetting.alpha = true;
|
||
viewer.start();
|
||
resolve(viewer);
|
||
}
|
||
);
|
||
});
|
||
};
|
||
|
||
const initForge = () => {
|
||
initViewer(forgeDom.value).then((viewer) => {
|
||
const localFilePath =
|
||
import.meta.env.MODE === "production"
|
||
? `${FILE_BASEURL}/upload/forge/0.svf`
|
||
: "/forge/0.svf";
|
||
loadModel(viewer, localFilePath).then(() => {
|
||
viewer.addEventListener(
|
||
Autodesk.Viewing.GEOMETRY_LOADED_EVENT,
|
||
async function () {
|
||
console.log(
|
||
"Autodesk.Viewing.GEOMETRY_LOADED_EVENT",
|
||
viewer.isLoadDone()
|
||
);
|
||
updateForgeViewer(viewer);
|
||
|
||
const tree = viewer.model.getData().instanceTree;
|
||
hideAllObjects(tree, visibleDbid.value);
|
||
|
||
// 印出被點選物件的 dbid
|
||
// viewer.addEventListener(
|
||
// Autodesk.Viewing.SELECTION_CHANGED_EVENT,
|
||
// function (event) {
|
||
// console.log("你選取的 forge_dbid:", event.dbIdArray);
|
||
// }
|
||
// );
|
||
}
|
||
);
|
||
viewer.addEventListener(
|
||
Autodesk.Viewing.CAMERA_CHANGE_EVENT,
|
||
function (e) {
|
||
viewer.isLoadDone() && updateDbidPosition(this, subscribeData.value);
|
||
console.log(
|
||
"camera position changed: ",
|
||
NOP_VIEWER.navigation.getTarget(),
|
||
e.camera.position
|
||
);
|
||
}
|
||
);
|
||
});
|
||
});
|
||
};
|
||
|
||
onMounted(() => {
|
||
console.log("Forge 加載");
|
||
initForge();
|
||
});
|
||
|
||
// 傳遞目前點擊資訊
|
||
const currentInfoModalData = ref(null);
|
||
const isMobile = (pointerType) => {
|
||
return pointerType !== "mouse"; // is desktop
|
||
};
|
||
const getCurrentInfoModalData = (e, position, value) => {
|
||
const mobile = isMobile(e.pointerType);
|
||
currentInfoModalData.value = {
|
||
initPos: mobile
|
||
? { left: `50%`, top: `50%` }
|
||
: { left: `${position.left}px`, top: `${position.top}px` },
|
||
value,
|
||
isMobile: mobile,
|
||
};
|
||
forge_info_modal.showModal();
|
||
};
|
||
|
||
watch([forgeViewer, forgeLock], ([newViewer, newLock]) => {
|
||
if (newViewer && newLock !== undefined) {
|
||
newViewer.setNavigationLock(newLock); // 鎖定視角
|
||
newViewer.navigation.setZoomTowardsPivot(!newLock); // 滾輪縮放
|
||
newViewer.navigation.setReverseZoomDirection(newLock); // 滑動變更視角
|
||
}
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
console.log("Forge 銷毀");
|
||
console.log("sub", subComponents);
|
||
subComponents.value?.unsubscribeAll();
|
||
subComponents.value?.detach();
|
||
updateForgeViewer(null);
|
||
NOP_VIEWER.tearDown();
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<ForgeInfoModal :data="currentInfoModalData" />
|
||
<div
|
||
:class="
|
||
twMerge(
|
||
fullScreen
|
||
? 'absolute top-0 left-0 w-screen h-full z-0'
|
||
: 'w-full relative'
|
||
)
|
||
"
|
||
>
|
||
<div
|
||
id="forge-preview"
|
||
ref="forgeDom"
|
||
:class="
|
||
twMerge(
|
||
'relative w-full h-full',
|
||
fullScreen ? 'min-h-screen ' : 'min-h-[600px]'
|
||
)
|
||
"
|
||
>
|
||
<div v-show="heat_bar_isShow" class="absolute z-10 heatbar">
|
||
<div class="w-40 flex justify-between text-[10px] mb-1">
|
||
<span class="text-gradient-1">-20°C</span>
|
||
<span class="text-gradient-2">0°C</span>
|
||
<span class="text-gradient-3">20°C</span>
|
||
<span class="text-gradient-4">40°C</span>
|
||
</div>
|
||
<div
|
||
class="w-40 h-3"
|
||
style="
|
||
background: linear-gradient(
|
||
to right,
|
||
#0000ff 0%,
|
||
#00ff00 33%,
|
||
#ffff00 66%,
|
||
#ff0000 100%
|
||
);
|
||
"
|
||
></div>
|
||
</div>
|
||
|
||
<label
|
||
v-for="(value, key) in subscribeDataWithErrorMsg"
|
||
:key="key"
|
||
:data-dbid="value.forge_dbid"
|
||
:class="
|
||
twMerge(
|
||
`after:border-t-[${value.currentColor}]`,
|
||
'flex items-center justify-center h-12 -translate-x-1/2 -translate-y-1/5 absolute z-50 px-5 py-4 text-center rounded-md text-lg border-2 border-white',
|
||
'after:absolute after:border-t-[10px] after:border-x-[12px] after:border-x-transparent after:-bottom-[8px] after:left-1/2 after:-translate-x-1/2 ',
|
||
'before:absolute before:border-t-[12px] before:border-x-[14px] before:border-x-transparent before:-bottom-[12px] before:left-1/2 before:-translate-x-1/2 before:border-white'
|
||
)
|
||
"
|
||
:style="{
|
||
left: `${Math.floor(value.device_coordinate_3d.x)}px`,
|
||
top: `${Math.floor(value.device_coordinate_3d.y) - 100}px`,
|
||
display: value.is_show,
|
||
backgroundColor: value.currentColor,
|
||
}"
|
||
@click.prevent="
|
||
(e) =>
|
||
getCurrentInfoModalData(
|
||
e,
|
||
{ left: e.clientX, top: e.clientY },
|
||
value
|
||
)
|
||
"
|
||
>
|
||
<span class="mr-2">{{ value.full_name }}</span>
|
||
<span v-if="value.alarmMsg">{{ value.alarmMsg }}</span>
|
||
<span v-else>{{ value.show_value }}</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style lang="css">
|
||
.adsk-viewing-viewer {
|
||
background-color: transparent !important;
|
||
}
|
||
|
||
#guiviewer3d-toolbar {
|
||
display: none;
|
||
bottom: 200px;
|
||
}
|
||
|
||
.viewcubeWrapper {
|
||
right: v-bind("`${props.cubeStyle.right}%`") !important;
|
||
top: v-bind("`${props.cubeStyle.top}%`") !important;
|
||
}
|
||
|
||
.homeViewWrapper {
|
||
transform: scale(1.5) !important;
|
||
}
|
||
|
||
.heatbar {
|
||
right: v-bind("`${props.cubeStyle.right + 2}%`") !important;
|
||
top: 0% !important;
|
||
}
|
||
</style>
|