import { onMounted, ref, computed, watch, markRaw, inject } from "vue"; import { getDashboardDevice } from "@/apis/dashboard"; import useSearchParams from "@/hooks/useSearchParam"; import useSystemHeatmap from "./useSystemHeatmap"; export default function useSystemStatusByBaja(updateHeatBarIsShow) { const rawData = ref([]); const forgeViewer = ref(null); const urn = ref(""); const { searchParams } = useSearchParams(); const initialData = ref(null); const updateInitialData = (data = false) => { initialData.value = data; }; const { updateHeatMapData, updateTemp, initHeatMap } = useSystemHeatmap(updateHeatBarIsShow); const updateForgeViewer = (viewer) => { if (!viewer) { forgeViewer.value = null; return; } forgeViewer.value = markRaw(viewer); initHeatMap(viewer); }; const getSubPoint = (normal, close, error, sub_points) => { let points = { ...Object.fromEntries(sub_points.map((p) => [p, ""])), }; if (normal) points[normal] = ""; if (close) points[close] = ""; if (error) points[error] = ""; return points; }; const subscribeData = ref({}); watch(rawData, () => { let sub_data = {}; rawData.value.forEach((d) => { sub_data = { ...sub_data, ...Object.fromEntries( d.device.map((dev) => [ dev.device_number, { ...dev, labelText: d.labelText, show_value: d.labelText, device_normal_point_name: d.device_normal_point_name, device_close_point_name: d.device_close_point_name, device_error_point_name: d.device_error_point_name, device_normal_point_value: d.device_normal_point_value, device_close_point_value: d.device_close_point_value, device_error_point_value: d.device_error_point_value, device_normal_color: d.device_normal_color, device_close_color: d.device_close_color, device_error_color: d.device_error_color, forge_dbid: parseInt(dev.forge_dbid), device_coordinate_3d: dev.device_coordinate_3d ? JSON.parse(dev.device_coordinate_3d) : { x: 0, y: 0 }, points: getSubPoint( d.device_normal_point_name, d.device_close_point_name, d.device_error_point_name, d.points ), is_show: true, currentColor: d.device_normal_color, }, ]) ), }; }); subscribeData.value = sub_data; updateHeatMapData(sub_data); updateSubscribeDataFromBaja(sub_data); }); const visibleDbid = computed(() => { let visible = []; rawData.value.forEach((d) => { visible = [ ...visible, ...d.device.map((dev) => parseInt(dev.forge_dbid)), ]; }); return visible; }); const getDevice = async (option = 1) => { const res = await getDashboardDevice({ option: parseInt(option), }); rawData.value = res.data.map((d) => ({ ...d, key: d.subSys, })); }; // subscribe from baja const booleanPointFacets = ref({}); const updateFacets = (point, facets) => { booleanPointFacets.value = { ...booleanPointFacets, [point]: facets, }; }; const updateDeviceData = (device_number, point, value) => { const correspondPoint = initialData.value.points.find( ({ name }) => name === point ); // console.log("sub 回傳值 ", typeof value) const text = correspondPoint ? correspondPoint.values.find( ({ value: pValue }) => pValue === parseInt(value) )?.text || "" : value; // console.log("sub", correspondPoint, device_number, point, value); subscribeData.value[device_number].points[point] = text; if ( point.toLowerCase() === "temp" && parseInt(searchParams.value.option) > 1 ) { updateTemp(device_number, value); } if (point === subscribeData.value[device_number].device_error_point_name) { subscribeData.value[device_number].currentColor = value === subscribeData.value[device_number].device_error_point_value ? subscribeData.value[device_number].device_error_color : subscribeData.value[device_number].device_normal_color; } updateLabelText(device_number, point, text); }; const transformDeviceNumber = (device_number) => { return device_number.replaceAll("_", "/"); }; const updateLabelText = (key, point, value) => { let text = subscribeData.value[key].labelText.replace(`%${point}`, value); Object.keys(subscribeData.value[key].points) .filter((p) => p !== point) .forEach((p) => { text = text.replace(`%${p}`, subscribeData.value[key].points[p]); }); subscribeData.value[key].show_value = text; }; const subComponents = ref(null); const updateSubscribeDataFromBaja = (data) => { for (let [key, value] of Object.entries(data)) { window.require && window.requirejs(["baja!"], (baja) => { console.log("進入 bajaSubscriber 準備執行BQL訂閱"); const ordPath = transformDeviceNumber(key); baja.Ord.make(`local:|foxs:|station:|slot:/${ordPath}`) .get() .then((folder) => { const batch = new baja.comm.Batch(); const sub = new baja.Subscriber(); sub.attach({ changed: function (prop, cx) { if (prop.$getDisplayName() !== "Out") return; if ( Object.hasOwn( booleanPointFacets.value, prop.$complex.$propInParent.$slotName ) ) { const facets = booleanPointFacets.value[ prop.$complex.$propInParent.$slotName ]; for (let [facetKey, facetValue] of Object.entries(facets)) { if (facetValue === prop.$getValue().getValueDisplay()) { updateDeviceData( key, prop.$complex.$propInParent.$slotName, facetKey ); } } } else { updateDeviceData( key, prop.$complex.$propInParent.$slotName, prop.$getValue().getValueDisplay() ); } }, }); folder .getSlots() .is("control:ControlPoint") .eachValue((point) => { if ( Object.keys(value.points).includes(point.getDisplayName()) ) { baja.Ord.make( `local:|foxs:|station:|slot:/${ordPath}/${point.getDisplayName()}` ) .get() .then((component) => { if ( point.getType().getTypeSpec() === "control:BooleanWritable" ) { const facets = component.getFacets1().toObject(); updateFacets(point.getDisplayName(), facets); for (let [facetKey, facetValue] of Object.entries( facets )) { if ( facetValue === component.getOut().getValue().toString() ) { updateDeviceData( key, point.getDisplayName(), facetKey ); } } } else { updateDeviceData( key, point.getDisplayName(), component.getOut().getValue() ); } sub .subscribe({ comps: component, // Can also just be an singular Component instance batch, // if defined, any network calls will be batched into this object (optional) }) .then(() => { console.log("subscribed successfully"); subComponents.value = sub; }) .catch(function (err) { baja.error( "some components failed to subscribe: " + err ); }); }); } }); }); }); } }; const updateDbidPosition = (viewer, data) => { if (!viewer) return; if (!forgeViewer.value) forgeViewer.value = markRaw(viewer); const tree = viewer.model.getData().instanceTree; const fragList = viewer.model.getFragmentList(); for (let [key, value] of Object.entries(data)) { const nodebBox = new window.THREE.Box3(); // for each fragId on the list, get the bounding box tree.enumNodeFragments( value.forge_dbid, (fragId) => { const fragbBox = new window.THREE.Box3(); fragList.getWorldBounds(fragId, fragbBox); nodebBox.union(fragbBox); // create a unifed bounding box }, true ); subscribeData.value[key].device_coordinate_3d = viewer.worldToClient( nodebBox.getCenter() ); subscribeData.value[key].is_show = viewer.isNodeVisible(value.forge_dbid); } }; const fitToView = () => { if(!searchParams.value.camera_position) return const { x, y, z } = JSON.parse(searchParams.value.camera_position); const newPosition = new THREE.Vector3(x, y, z); //!<<< 相机的新位置 const { x: x1, y: y1, z: z1, } = JSON.parse(searchParams.value.target_position); //!<<< 计算新焦点位置 const newTarget = new THREE.Vector3(x1, y1, z1); //!<<< 焦點的新位置 forgeViewer.value.navigation.getCamera().setView({ position: newPosition.clone(), target: newTarget.clone(), }); setTimeout(() => { updateDbidPosition(forgeViewer.value, subscribeData.value); }, 700); }; const hideAllObjects = (instanceTree, filDbids = []) => { const tree = instanceTree || forgeViewer.value.model?.getInstanceTree(); const allDbIdsStr = Object.keys(tree.nodeAccess.dbIdToIndex); for (var i = 0; i < allDbIdsStr.length; i++) { forgeViewer.value.hide(parseInt(allDbIdsStr[i])); } for (var i = 0; i < filDbids.length; i++) { forgeViewer.value.show(parseInt(filDbids[i])); } fitToView(); forgeViewer.value.impl.invalidate(true); }; const loadModel = (viewer, urn) => { return new Promise(function (resolve, reject) { async function onDocumentLoadSuccess(doc) { viewer.setGroundShadow(false); viewer.impl.renderer().setClearAlpha(0); //clear alpha channel viewer.impl.glrenderer().setClearColor(0xffffff, 0); //set transparent background, color code does not matter viewer.impl.invalidate(true); //trigger rendering const documentNode = await viewer.loadDocumentNode( doc, doc.getRoot().getDefaultGeometry() ); resolve(documentNode); } function onDocumentLoadFailure(code, message, errors) { reject({ code, message, errors }); } Autodesk.Viewing.Document.load( "urn:" + urn, onDocumentLoadSuccess, onDocumentLoadFailure ); }); }; const reloadModal = () => {}; watch(visibleDbid, (newValue) => { forgeViewer.value && hideAllObjects(forgeViewer.value.model.getData().instanceTree, newValue); }); watch(initialData, (newValue) => { if (newValue) { getDevice(searchParams.value.option); } }); watch( searchParams, (newValue) => { getDevice(newValue.option); }, { deep: true, } ); return { subscribeData, visibleDbid, updateDbidPosition, hideAllObjects, updateForgeViewer, loadModel, urn, updateInitialData, subComponents, }; }