import { useEffect, useRef, useState } from "react"; import * as BABYLON from "@babylonjs/core"; import "@babylonjs/core/Debug/debugLayer"; import "@babylonjs/inspector"; import "@babylonjs/loaders/glTF"; import { GridMaterial } from "@babylonjs/materials/"; import { HemisphericLight, Vector3 } from "@babylonjs/core"; import { useAppSelector } from "../store/hooks"; import "../page/style/standard.css"; import EqInfoData from "./EqInfoData"; import AlarmTipGreen from "./../page/assets/icon/g.png"; import AlarmTipYellow from "./../page/assets/icon/y.png"; import AlarmTipRed from "./../page/assets/icon/r.png"; import {selectLine1Before} from "../store/LinePageSlice"; const lineNameNo = ["一","二","三","四","五"] const myStyle = { width: "1041px", height: "562px", outline: "none", }; interface MybabylonJSProps { modelPath: string; // 明确 modelPath 属性的类型为 string } interface EqListType { [key: string]: EqMsg } interface EqMsg { equipmentName?:string; run?:boolean; error?:boolean; inputNum?:number; outputNum?:number; quantityTime?:number; status?:string; statusTime?:number; localDateTime?:number; equipmentCode?:string; equipmentId?:number; } function MybabylonJS({ modelPath }: MybabylonJSProps) { const [eqList, setEqList] = useState({}); const allData = useAppSelector(selectLine1Before) as any; // 使用`any`来绕过类型检查 const canvasRef = useRef(null); const resetRef = useRef<(() => void) | null>(null); const [selectedMeshName, setSelectedMeshName] = useState(null); const [selectedMeshId, setSelectedMeshId] = useState(null); const [selectedMeshObj, setSelectedMeshObj] = useState({ equipmentName: "", run: true, error: false, }); const [showInfo, setShowInfo] = useState(true); // 使用 useRef 来存储当前加载的模型引用 const currentMeshesRef = useRef>([]); useEffect(() => { const equStatus = allData?.equStatus; if (equStatus) { setEqList(equStatus); } },[allData]) useEffect(() => { const equStatus = allData?.equStatus; if (equStatus) { for (let i = 0; i < EqInfoData[modelPath].length; i++) { for (let j = 0; j < EqInfoData[modelPath][i].data.length; j++) { EqInfoData[modelPath][i].data[j].value = equStatus[EqInfoData[modelPath][i].data[j].code][EqInfoData[modelPath][i].data[j].label] ? equStatus[EqInfoData[modelPath][i].data[j].code][EqInfoData[modelPath][i].data[j].label] : 0 } } } },[allData,modelPath]) useEffect(() => { if (selectedMeshId && eqList[selectedMeshId]) { setSelectedMeshObj({ equipmentName:eqList[selectedMeshId].equipmentName, run:eqList[selectedMeshId].run ? eqList[selectedMeshId].run : true, error:eqList[selectedMeshId].error ? eqList[selectedMeshId].error : false, }); } },[selectedMeshId]) useEffect(() => { // 确保 canvas 引用存在 if (!canvasRef.current) return; const canvas = canvasRef.current; const engine = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true, }); const createScene = async function () { // This creates a basic Babylon Scene object (non-mesh) const scene = new BABYLON.Scene(engine); scene.clearColor = new BABYLON.Color4(0, 0, 0, 0); const baseLight = new HemisphericLight( "hemiLight", new Vector3(-1, 1, 0), scene ); baseLight.intensity = 1; baseLight.diffuse = new BABYLON.Color3(1, 1, 1); baseLight.specular = new BABYLON.Color3(0.25, 0.25, 0.25); baseLight.groundColor = new BABYLON.Color3(0.5, 0.5, 0.5); //add an arcRotateCamera to the scene const camera = new BABYLON.ArcRotateCamera( "camera", BABYLON.Tools.ToRadians(245), BABYLON.Tools.ToRadians(25), modelPath.slice(-3) === "2-1" ? 120 : modelPath.slice(-1) === "1" ? 110 : modelPath.slice(-3) === "5-2" ? 100 : modelPath.slice(-3) === "1-2" ? 90 : 65, new BABYLON.Vector3(-13, 0, 0) ); camera.lowerRadiusLimit = 10; camera.upperRadiusLimit = 600; // This attaches the camera to the canvas camera.attachControl(canvas, true); //创建一个材质 const newMt = new BABYLON.StandardMaterial("newMt"); newMt.diffuseColor = BABYLON.Color3.Blue(); const ground = BABYLON.MeshBuilder.CreateGround( "ground", { width: 1000, height: 1000, subdivisions: 1, }, scene ); ground.scaling.x = 100; ground.scaling.z = ground.scaling.x; ground.isPickable = false; let grid = new GridMaterial("grid", scene); grid.majorUnitFrequency = 10; grid.minorUnitVisibility = 0.3; grid.gridRatio = 0.04; grid.backFaceCulling = !1; grid.mainColor = new BABYLON.Color3(1, 1, 1); grid.lineColor = new BABYLON.Color3(1, 1, 1); grid.opacity = 0; grid.zOffset = 1; grid.opacityTexture = new BABYLON.Texture( "/public/png/backgroundGround.png", scene ); ground.material = grid; let hl = new BABYLON.HighlightLayer("hl1", scene); let hl2 = new BABYLON.HighlightLayer("hl2", scene); // 定义一个函数来加载或重新加载模型 const loadOrReloadModel = async () => { // 在加载新模型之前卸载已加载的模型 currentMeshesRef.current.forEach((mesh) => { if (mesh && mesh.parent) { scene.removeMesh(mesh, true); } }); currentMeshesRef.current = []; // 重置模型数组 try { // 使用 ImportMeshAsync 加载新模型 var LOD0MESH = await BABYLON.SceneLoader.ImportMeshAsync( "", "/Line/", `${modelPath}.babylon`, scene ); // 将新加载的模型添加到 currentMeshesRef 中 currentMeshesRef.current.push(...LOD0MESH.meshes); // ...为新加载的模型设置交互逻辑 LOD0MESH.meshes.map((mesh) => { mesh.isPickable = true; mesh.actionManager = new BABYLON.ActionManager(scene); if (modelPath.slice(-1) === "1") { if ( mesh.name.includes("磨边") || mesh.name.includes("清洗") || mesh.name.includes("镀膜") || mesh.name.includes("固化") || mesh.name.includes("丝印") || mesh.name.includes("打孔") ) { // @ts-ignore hl.addMesh(mesh, BABYLON.Color3.Green()); } } else { if ( mesh.name.includes("钢化") || mesh.name.includes("包装") || mesh.name.includes("铺纸") || mesh.name.includes("下片机械手") ) { // @ts-ignore hl.addMesh(mesh, BABYLON.Color3.Green()); } } mesh._scene.onPointerDown = async (event, _pickResult) => { console.log('_pickResult',_pickResult) const pickInfo = mesh._scene.pick( mesh._scene.pointerX, mesh._scene.pointerY ); //判断是否是右键 if (!(event.buttons === 1 && pickInfo.pickedMesh)) return; const MeshName = pickInfo.pickedMesh.name; const MeshNameId = pickInfo.pickedMesh.metadata.tags; setSelectedMeshName(MeshName); setSelectedMeshId(MeshNameId); }; }); } catch (error) { console.error("加载模型失败:", error); } }; // 调用函数以加载或重新加载模型 loadOrReloadModel(); function reset() { camera.target = new BABYLON.Vector3(-13, 0, 0); camera.alpha = BABYLON.Tools.ToRadians(245); camera.beta = BABYLON.Tools.ToRadians(25); camera.radius = modelPath.slice(-3) === "2-1" ? 120 : modelPath.slice(-1) === "1" ? 110 : modelPath.slice(-3) === "5-2" ? 100 : modelPath.slice(-3) === "1-2" ? 90 : 65 setShowInfo(true); setSelectedMeshName(null); } // 外部初始位置按钮 resetRef.current = reset; let resetCamera = setTimeout(reset, 15000); scene.onPointerObservable.add((pointerInfo) => { switch (pointerInfo.type) { case BABYLON.PointerEventTypes.POINTERMOVE: clearTimeout(resetCamera); resetCamera = setTimeout(reset, 15000); setShowInfo(false); } }); return scene; }; // call the createScene function const scene = createScene(); // run the render loop scene.then( (scene) => { console.log("createScene被调用了=====", scene); engine.runRenderLoop(function () { scene.render(); }); }, (reason) => { console.log("reason=============", reason); } ); // Resize window.addEventListener("resize", function () { engine.resize(); }); // 组件卸载时的清理逻辑 return () => { // 清理场景和引擎资源 engine.dispose(); }; }, [modelPath]); const resetModel = () => { //模型初始位置 if (resetRef.current) { resetRef.current(); } }; return (
{/*

当前选择: {selectedMeshName}

*/}
第{lineNameNo[Number(modelPath.slice(-3,-2))-1]}产线钢化{modelPath.slice(-1) === "1" ? "前段" : "后段"}
{selectedMeshName && (
设备名称: {selectedMeshObj.equipmentName}
报警状态: {selectedMeshObj.error ? ( <> 报警 ) : ( <> 正常 )}
在线状态: {selectedMeshObj.run ? ( <> 在线 ) : ( <> 离线 )}
)} {showInfo && EqInfoData[modelPath] && EqInfoData[modelPath].map((item) => { return (
{item.name}
{item.data.map((info) => { return (
{info.name}:{info.value}
); })}
); })}
); } export default MybabylonJS;