Pārlūkot izejas kodu

新增主斜井管控详情页面

hongrunxia 8 mēneši atpakaļ
vecāks
revīzija
f7d49006f9

BIN
public/model/glft/ztfj/ztfj-xj_2024-06-20.glb


+ 1 - 0
src/utils/threejs/main.worker.ts

@@ -54,6 +54,7 @@ export function initModalWorker() {
     'ztfj/fbm_2023-06-02.glb',
     'ztfj/ztfj-fc_2023-06-02.glb',
     'ztfj/ztfj_2023-12-12.glb',
+    'ztfj/ztfj-xj_2024-06-20.glb',
     'fire/laneway_2024-03-04.glb',
     'fire/laneway-device_2024-03-19.glb',
     'fire/chamber_2023-06-02.glb',

+ 2 - 0
src/views/vent/monitorManager/fanLocalMonitor/index.vue

@@ -1222,6 +1222,8 @@
             // m3: selectData.m3 || 675.87,
             m3: 675.87,
             frequency: 30,
+            // m3: 525.87,  //5.0测试数据
+            // frequency: 35,
             // frequency: selectData.Fan1fHz || selectData.Fan1FreqHz || selectData.Fan1Loop_Frequency,
             gasWarningVal: gasWarningVal.value,
             isCompute: false,

+ 4 - 2
src/views/vent/monitorManager/mainFanMonitor/index.vue

@@ -649,12 +649,11 @@
     loading.value = true;
     const baseDataIndex: any = dataSource.value.findIndex((baseData: any) => baseData.deviceID === id);
     selectRowIndex.value = baseDataIndex;
-    const type = 'mainWindRect';
+
     for (const key in selectData) {
       selectData[key] = '';
     }
     nextTick(async () => {
-      await setModelType(type);
       loading.value = false;
       if (!headElHeight.value) {
         const headEl = document.querySelector(`.zxm-table-thead`);
@@ -671,6 +670,9 @@
         selectDevice('dataMonitorRowIndex', 1);
       }
       Object.assign(selectData, data);
+      const type = selectData['modalTyoe'] === 'xiejing' ? 'mainXjWindRect' : 'mainWindRect';
+
+      await setModelType(type);
     });
     await getCamera(id, playerRef.value);
     return;

+ 185 - 161
src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts

@@ -2,6 +2,7 @@ import * as THREE from 'three';
 import { animateCamera } from '/@/utils/threejs/util';
 import UseThree from '../../../../utils/threejs/useThree';
 import mainWindRect from './mainWind.threejs';
+import mainXjWindRect from './mainWind.xj.threejs';
 import useEvent from '../../../../utils/threejs/useEvent';
 
 // import * as dat from 'dat.gui';
@@ -13,7 +14,8 @@ let model: UseThree | undefined, //
   group: THREE.Object3D | undefined,
   bgGroup: THREE.Object3D | undefined,
   mainWindObj: mainWindRect | undefined,
-  modalType = 'mainWind',
+  mainXjWindObj: mainXjWindRect | undefined,
+  modalType = 'mainWindRect',
   explosionVentClose = -1,
   explosionVentOpen = -1;
 
@@ -34,29 +36,6 @@ const addLight = () => {
   pointLight7.position.set(21, 64, 75);
   pointLight7.shadow.bias = -0.05;
   model?.scene?.add(pointLight7);
-
-  // const spotLight = new THREE.SpotLight();
-  // spotLight.angle = Math.PI / 16;
-  // spotLight.penumbra = 0;
-  // // spotLight.castShadow = true;
-  // spotLight.position.set(500, 500, 687);
-  // model?.scene?.add(spotLight);
-
-  // spotLight.shadow.camera.near = 0.5; // default
-  // spotLight.shadow.camera.far = 1000; // default
-  // spotLight.shadow.focus = 1;
-  // spotLight.shadow.bias = -0.000002;
-
-  // gui.add(pointLight7.position, 'x', -1000, 1000);
-  // gui.add(pointLight7.position, 'y', -1000, 1000);
-  // gui.add(pointLight7.position, 'z', -1000, 1000);
-  // gui.add(spotLight.shadow, 'bias', -1, 1);
-  // gui.add(spotLight.shadow, 'focus', -2, 2);
-  // gui.add(pointLight7, 'distance', 0, 1000);
-
-  // gui.add(pointLight6.position, 'x', -500, 500);
-  // gui.add(pointLight6.position, 'y', -500, 500);
-  // gui.add(pointLight6.position, 'z', -500, 500);
 };
 
 // 重置摄像头
@@ -88,8 +67,10 @@ const mouseEvent = (event) => {
   if (event.button == 0) {
     model?.canvasContainer?.addEventListener('mousemove', mousemove);
     mouseDownFn(<UseThree>model, <THREE.Object3D>group, event, (intersects) => {
-      if (modalType === 'mainWindRect') {
-        mainWindObj.mousedownModel.call(mainWindObj, intersects);
+      if (modalType === 'mainWindRect' && mainWindObj) {
+        mainWindObj?.mousedownModel.call(mainWindObj, intersects);
+      } else if (modalType === 'mainXjWindRect' && mainXjWindObj) {
+        mainXjWindObj?.mousedownModel.call(mainXjWindObj, intersects);
       }
     });
   }
@@ -110,6 +91,8 @@ export const addText = () => {
   if (!mainWindObj) return;
   if (modalType === 'mainWindRect' && mainWindObj) {
     return mainWindObj.addCssText.call(mainWindObj);
+  } else if (modalType === 'mainXjWindRect' && mainXjWindObj) {
+    return mainXjWindObj.addCssText.call(mainXjWindObj);
   }
 };
 
@@ -118,6 +101,8 @@ export const resetEcharts = (selectData) => {
   if (!mainWindObj) return;
   if (modalType === 'mainWindRect' && mainWindObj) {
     return mainWindObj.addEcharts.call(mainWindObj);
+  } else if (modalType === 'mainXjWindRect' && mainXjWindObj) {
+    return mainXjWindObj.addEcharts.call(mainXjWindObj);
   }
 };
 
@@ -134,84 +119,91 @@ export const play = (controlType, deviceType, frequencyVal?, state?, smokeDirect
   if (!mainWindObj) return;
   if (modalType === 'mainWindRect' && mainWindObj) {
     return mainWindObj.playSmoke.call(mainWindObj, controlType, deviceType, frequencyVal, state, smokeDirection);
+  } else if (modalType === 'mainXjWindRect' && mainXjWindObj) {
+    return mainXjWindObj.playSmoke.call(mainXjWindObj, controlType, deviceType, frequencyVal, state, smokeDirection);
   }
 };
 
 export const playAnimate1 = async (selectData, duration?) => {
   if (!mainWindObj) return;
+  let mainObj: mainWindRect | mainXjWindRect | undefined;
+
   if (modalType === 'mainWindRect') {
-    if (selectData) {
-      if (selectData.Fan1WindowOpen !== undefined) {
-        // 主风机水平窗开启
-        if (selectData.Fan1WindowOpen == 1) mainWindObj?.openOrCloseWindow('front', 'openWindow');
-        if (selectData.Fan1WindowOpen == 0) mainWindObj?.openOrCloseWindow('front', 'closeWindow');
-      }
-      if (selectData.Fan2WindowOpen !== undefined) {
-        // 备风机水平窗开启
-        if (selectData.Fan2WindowOpen == 1) mainWindObj?.openOrCloseWindow('back', 'openWindow');
-        if (selectData.Fan2WindowOpen == 0) mainWindObj?.openOrCloseWindow('back', 'closeWindow');
-      }
-      if (selectData.Fan1ButterflyOpen !== undefined) {
-        if (selectData.Fan1ButterflyOpen == 1) {
-          // 主风机蝶阀打开
-          mainWindObj.openOrCloseValve('front', 'open', duration);
-        } else {
-          // 主风机蝶阀关闭
-          mainWindObj.openOrCloseValve('front', 'close', duration);
-        }
+    mainObj = mainWindObj;
+  } else if (modalType === 'mainXjWindRect') {
+    mainObj = mainXjWindObj;
+  }
+  if (selectData && mainObj) {
+    if (selectData.Fan1WindowOpen !== undefined) {
+      // 主风机水平窗开启
+      if (selectData.Fan1WindowOpen == 1) mainObj?.openOrCloseWindow('front', 'openWindow');
+      if (selectData.Fan1WindowOpen == 0) mainObj?.openOrCloseWindow('front', 'closeWindow');
+    }
+    if (selectData.Fan2WindowOpen !== undefined) {
+      // 备风机水平窗开启
+      if (selectData.Fan2WindowOpen == 1) mainObj?.openOrCloseWindow('back', 'openWindow');
+      if (selectData.Fan2WindowOpen == 0) mainObj?.openOrCloseWindow('back', 'closeWindow');
+    }
+    if (selectData.Fan1ButterflyOpen !== undefined) {
+      if (selectData.Fan1ButterflyOpen == 1) {
+        // 主风机蝶阀打开
+        mainObj.openOrCloseValve('front', 'open', duration);
+      } else {
+        // 主风机蝶阀关闭
+        mainObj.openOrCloseValve('front', 'close', duration);
       }
-      if (selectData.Fan2ButterflyOpen !== undefined) {
-        if (selectData.Fan2ButterflyOpen == 1) {
-          // 主风机蝶阀打开
-          mainWindObj.openOrCloseValve('back', 'open', duration);
-        } else {
-          // 主风机蝶阀关闭
-          mainWindObj.openOrCloseValve('back', 'close', duration);
-        }
+    }
+    if (selectData.Fan2ButterflyOpen !== undefined) {
+      if (selectData.Fan2ButterflyOpen == 1) {
+        // 主风机蝶阀打开
+        mainObj.openOrCloseValve('back', 'open', duration);
+      } else {
+        // 主风机蝶阀关闭
+        mainObj.openOrCloseValve('back', 'close', duration);
       }
+    }
 
-      if (selectData.Fan1FreqHz !== undefined) {
-        // 主风机频率设置
-        mainWindObj.resetSmokeParam('front', selectData.Fan1FreqHz, duration);
-      }
-      if (selectData.Fan2FreqHz !== undefined) {
-        // 主风机频率设置
-        mainWindObj.resetSmokeParam('back', selectData.Fan2FreqHz, duration);
-      }
-      if (selectData.Fan1StartStatus) {
-        if (selectData.Fan1StartStatus == 1) {
-          // 主风机开启
-          mainWindObj.lookMotor('front', 'open', duration);
+    if (selectData.Fan1FreqHz !== undefined) {
+      // 主风机频率设置
+      mainObj.resetSmokeParam('front', selectData.Fan1FreqHz, duration);
+    }
+    if (selectData.Fan2FreqHz !== undefined) {
+      // 主风机频率设置
+      mainObj.resetSmokeParam('back', selectData.Fan2FreqHz, duration);
+    }
+    if (selectData.Fan1StartStatus) {
+      if (selectData.Fan1StartStatus == 1) {
+        // 主风机开启
+        mainObj.lookMotor('front', 'open', duration);
 
-          // if (selectData.Fan1FreqForwardRun && selectData.Fan1FreqForwardRun == 1) {
-          //   // 主风机正转
-          //   await mainWindObj.setSmokeDirection('front', 'tubPositivePath');
-          // } else if (selectData.Fan1FreqReverseRun && selectData.Fan1FreqReverseRun == 1) {
-          //   // 主风机反转
-          //   await mainWindObj.setSmokeDirection('front', 'tubInversePath');
-          // }
-          // 齿轮转动
-          mainWindObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
-          await mainWindObj.setSmokeDirection('front', 'tubPositivePath');
-          if (!mainWindObj.frontSmoke?.frameId) mainWindObj?.frontSmoke?.startSmoke(duration);
-        } else {
-          mainWindObj?.lookMotor('front', 'close', duration);
-        }
+        // if (selectData.Fan1FreqForwardRun && selectData.Fan1FreqForwardRun == 1) {
+        //   // 主风机正转
+        //   await mainWindObj.setSmokeDirection('front', 'tubPositivePath');
+        // } else if (selectData.Fan1FreqReverseRun && selectData.Fan1FreqReverseRun == 1) {
+        //   // 主风机反转
+        //   await mainWindObj.setSmokeDirection('front', 'tubInversePath');
+        // }
+        // 齿轮转动
+        mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
+        await mainObj.setSmokeDirection('front', 'tubPositivePath');
+        if (!mainObj.frontSmoke?.frameId) mainObj?.frontSmoke?.startSmoke(duration);
+      } else {
+        mainObj?.lookMotor('front', 'close', duration);
       }
-      if (selectData.Fan2StartStatus) {
-        if (selectData.Fan2StartStatus == 1) {
-          // 备风机开启
-          mainWindObj.lookMotor('back', 'open', duration);
-          // if (selectData.Fan2FreqForwardRun && selectData.Fan2FreqForwardRun == 1) {
-          //   // 主风机正转
-          // } else if (selectData.Fan2FreqReverseRun && selectData.Fan2FreqReverseRun == 1) {
-          //   // 主风机反转
-          // }
-          await mainWindObj.setSmokeDirection('back', 'tubPositivePath');
-          if (!mainWindObj.backSmoke?.frameId) mainWindObj?.backSmoke?.startSmoke(duration);
-        } else {
-          mainWindObj?.lookMotor('back', 'close', duration);
-        }
+    }
+    if (selectData.Fan2StartStatus) {
+      if (selectData.Fan2StartStatus == 1) {
+        // 备风机开启
+        mainObj.lookMotor('back', 'open', duration);
+        // if (selectData.Fan2FreqForwardRun && selectData.Fan2FreqForwardRun == 1) {
+        //   // 主风机正转
+        // } else if (selectData.Fan2FreqReverseRun && selectData.Fan2FreqReverseRun == 1) {
+        //   // 主风机反转
+        // }
+        await mainObj.setSmokeDirection('back', 'tubPositivePath');
+        if (!mainObj.backSmoke?.frameId) mainObj?.backSmoke?.startSmoke(duration);
+      } else {
+        mainObj?.lookMotor('back', 'close', duration);
       }
     }
   }
@@ -219,84 +211,91 @@ export const playAnimate1 = async (selectData, duration?) => {
 
 export const playAnimate = async (selectData, duration?) => {
   if (!mainWindObj) return;
+
+  let mainObj: mainWindRect | mainXjWindRect | undefined;
+
   if (modalType === 'mainWindRect') {
-    if (selectData) {
-      if (selectData['Fan1FreqHz'] == undefined || selectData['Fan1FreqHz'] == null || selectData['Fan1FreqHz'] == '') selectData['Fan1FreqHz'] = 50;
-      if (selectData['Fan2FreqHz'] == undefined || selectData['Fan2FreqHz'] == null || selectData['Fan2FreqHz'] == '') selectData['Fan2FreqHz'] = 50;
-      mainWindObj.resetSmokeParam('front', selectData.Fan1FreqHz, duration);
-      mainWindObj.resetSmokeParam('back', selectData.Fan2FreqHz, duration);
-      if (selectData.Fan1StartStatus == 1) {
-        // 主风机开启
-        mainWindObj?.lookMotor('front', 'open', duration);
-        mainWindObj?.openOrCloseValve('front', 'open', duration);
-        // 1. 已经运行,首次切入动画
-        // 2. 在页面上,切换动画
-        if (selectData.Fan1FreqForwardRun == 1 && selectData.Fan1FreqReverseRun == 0) {
-          // 主风机正转
-          mainWindObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
-          await mainWindObj.setSmokeDirection('front', 'tubPositivePath');
-        } else if (selectData.Fan1FreqReverseRun == 1 && selectData.Fan1FreqForwardRun == 0) {
-          // 主风机反转
-          mainWindObj.startGearAnimation('front', 'open', 'tubInversePath', selectData.Fan1FreqHz, duration);
-          await mainWindObj.setSmokeDirection('front', 'tubInversePath');
-        } else {
-          // 默认主风机正转
-          mainWindObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
-          await mainWindObj.setSmokeDirection('front', 'tubPositivePath');
-        }
+    mainObj = mainWindObj;
+  } else if (modalType === 'mainXjWindRect') {
+    mainObj = mainXjWindObj;
+  }
 
-        if (!mainWindObj?.frontSmoke?.frameId) mainWindObj?.frontSmoke?.startSmoke(duration);
+  if (selectData && mainObj) {
+    if (selectData['Fan1FreqHz'] == undefined || selectData['Fan1FreqHz'] == null || selectData['Fan1FreqHz'] == '') selectData['Fan1FreqHz'] = 50;
+    if (selectData['Fan2FreqHz'] == undefined || selectData['Fan2FreqHz'] == null || selectData['Fan2FreqHz'] == '') selectData['Fan2FreqHz'] = 50;
+    mainObj.resetSmokeParam('front', selectData.Fan1FreqHz, duration);
+    mainObj.resetSmokeParam('back', selectData.Fan2FreqHz, duration);
+    if (selectData.Fan1StartStatus == 1) {
+      // 主风机开启
+      mainObj?.lookMotor('front', 'open', duration);
+      mainObj?.openOrCloseValve('front', 'open', duration);
+      // 1. 已经运行,首次切入动画
+      // 2. 在页面上,切换动画
+      if (selectData.Fan1FreqForwardRun == 1 && selectData.Fan1FreqReverseRun == 0) {
+        // 主风机正转
+        mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
+        await mainObj.setSmokeDirection('front', 'tubPositivePath');
+      } else if (selectData.Fan1FreqReverseRun == 1 && selectData.Fan1FreqForwardRun == 0) {
+        // 主风机反转
+        mainObj.startGearAnimation('front', 'open', 'tubInversePath', selectData.Fan1FreqHz, duration);
+        await mainObj.setSmokeDirection('front', 'tubInversePath');
       } else {
-        // 主风机停止
-        mainWindObj.closeDevice('front');
+        // 默认主风机正转
+        mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
+        await mainObj.setSmokeDirection('front', 'tubPositivePath');
       }
-      if (selectData.Fan2StartStatus == 1) {
-        // 主风机开启
-        mainWindObj.lookMotor('back', 'open', duration);
-        mainWindObj.openOrCloseValve('back', 'open', duration);
-        // 1. 已经运行,首次切入动画
-        // 2. 在页面上,切换动画
-        if (selectData.Fan2FreqForwardRun == 1 && selectData.Fan2FreqReverseRun == 0) {
-          // 主风机正转
-          mainWindObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
-          await mainWindObj.setSmokeDirection('back', 'tubPositivePath');
-        } else if (selectData.Fan2FreqReverseRun == 1 && selectData.Fan2FreqForwardRun == 0) {
-          // 主风机反转
-          mainWindObj.startGearAnimation('back', 'open', 'tubInversePath', selectData.Fan2FreqHz, duration);
-          await mainWindObj.setSmokeDirection('back', 'tubInversePath');
-        } else {
-          mainWindObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
-          await mainWindObj.setSmokeDirection('back', 'tubPositivePath');
-        }
 
-        if (!mainWindObj?.backSmoke?.frameId) mainWindObj?.backSmoke?.startSmoke(duration);
+      if (!mainObj?.frontSmoke?.frameId) mainObj?.frontSmoke?.startSmoke(duration);
+    } else {
+      // 主风机停止
+      mainObj.closeDevice('front');
+    }
+    if (selectData.Fan2StartStatus == 1) {
+      // 主风机开启
+      mainObj.lookMotor('back', 'open', duration);
+      mainObj.openOrCloseValve('back', 'open', duration);
+      // 1. 已经运行,首次切入动画
+      // 2. 在页面上,切换动画
+      if (selectData.Fan2FreqForwardRun == 1 && selectData.Fan2FreqReverseRun == 0) {
+        // 主风机正转
+        mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+        await mainObj.setSmokeDirection('back', 'tubPositivePath');
+      } else if (selectData.Fan2FreqReverseRun == 1 && selectData.Fan2FreqForwardRun == 0) {
+        // 主风机反转
+        mainObj.startGearAnimation('back', 'open', 'tubInversePath', selectData.Fan2FreqHz, duration);
+        await mainObj.setSmokeDirection('back', 'tubInversePath');
       } else {
-        // 主风机停止
-        mainWindObj.closeDevice('back');
+        mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+        await mainObj.setSmokeDirection('back', 'tubPositivePath');
       }
 
-      // 防爆门动画
-      if (selectData['ExplosionVentOpen'] == 1 && explosionVentOpen !== 1) {
-        if (explosionVentOpen == -1) {
-          // 直接打开
-          mainWindObj.playAnimation('open', 0);
-        } else {
-          mainWindObj.playAnimation('open');
-        }
-        explosionVentOpen = 1;
-        explosionVentClose = 0;
-      }
-      if (selectData['ExplosionVentClose'] == 1 && explosionVentClose !== 1) {
-        if (explosionVentOpen == -1) {
-          // 直接关闭
-          mainWindObj.playAnimation('close', 0);
-        } else {
-          mainWindObj.playAnimation('close');
-        }
+      if (!mainObj?.backSmoke?.frameId) mainObj?.backSmoke?.startSmoke(duration);
+    } else {
+      // 主风机停止
+      mainObj.closeDevice('back');
+    }
 
-        explosionVentClose = 1;
-        explosionVentOpen = 0;
+    // 防爆门动画
+    if (modalType === 'mainWindRect' && selectData['ExplosionVentOpen'] == 1 && explosionVentOpen !== 1) {
+      if (explosionVentOpen == -1) {
+        // 直接打开
+        mainObj.playAnimation('open', 0);
+      } else {
+        mainObj.playAnimation('open');
       }
+      explosionVentOpen = 1;
+      explosionVentClose = 0;
+    }
+    if (modalType === 'mainWindRect' && selectData['ExplosionVentClose'] == 1 && explosionVentClose !== 1) {
+      if (explosionVentOpen == -1) {
+        // 直接关闭
+        mainObj.playAnimation('close', 0);
+      } else {
+        mainObj.playAnimation('close');
+      }
+
+      explosionVentClose = 1;
+      explosionVentOpen = 0;
     }
   }
 };
@@ -308,6 +307,8 @@ export const setModelType = (type) => {
   return new Promise((resolve) => {
     // 停止气流动画
     mainWindObj?.stopSmoke();
+    mainXjWindObj?.stopSmoke();
+    if (group) model?.scene?.remove(group);
     if (modalType === 'mainWindRect' && mainWindObj && mainWindObj.group) {
       (<UseThree>model).startAnimation = mainWindObj.render.bind(mainWindObj);
       group = mainWindObj.group;
@@ -327,6 +328,25 @@ export const setModelType = (type) => {
         if (group) model?.scene?.add(group);
       }, 300);
     }
+    if (modalType === 'mainXjWindRect' && mainXjWindObj && mainXjWindObj.group) {
+      (<UseThree>model).startAnimation = mainXjWindObj.render.bind(mainXjWindObj);
+      group = mainXjWindObj.group;
+      setTimeout(async () => {
+        resolve(null);
+        // const position = mainWindObj.group.position;
+        const position = new THREE.Vector3(-0.45, 0.84, -10.35);
+        const oldCameraPosition = { x: -332.39, y: 283.47, z: 438.61 };
+        await animateCamera(
+          oldCameraPosition,
+          { x: -3.41, y: -29.01, z: 8.84 },
+          { x: -1.23, y: 75.15, z: 118.36 },
+          { x: position.x, y: position.y, z: position.z },
+          model,
+          0.8
+        );
+        if (group) model?.scene?.add(group);
+      }, 300);
+    }
   });
 };
 
@@ -347,6 +367,8 @@ export const mountedThree = (playerVal1) => {
       model?.scene?.add(bgGroup);
       mainWindObj = new mainWindRect(model, playerVal1);
       await mainWindObj.mountedThree();
+      mainXjWindObj = new mainXjWindRect(model, playerVal1);
+      await mainXjWindObj.mountedThree();
       model?.animate();
       resolve(null);
     });
@@ -360,6 +382,8 @@ export const destroy = () => {
     console.log('场景销毁前信息----------->', model.renderer?.info);
     mainWindObj?.destroy();
     mainWindObj = undefined;
+    mainXjWindObj?.destroy();
+    mainXjWindObj = undefined;
     model.clearGroup(bgGroup);
     bgGroup = undefined;
     group = undefined;

+ 718 - 0
src/views/vent/monitorManager/mainFanMonitor/mainWind.xj.threejs.ts

@@ -0,0 +1,718 @@
+import * as THREE from 'three';
+import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
+import Smoke from '/@/views/vent/comment/threejs/Smoke';
+import { renderVideo } from '/@/utils/threejs/util';
+import gsap from 'gsap';
+
+class mainXjWindRect {
+  model;
+  modelName = 'mainXjWindRect';
+  group: THREE.Group | null = null; // 主通风机场景
+  motorGroup1: THREE.Group | null = null; //电机
+  motorGroup2: THREE.Group | null = null; //电机
+  gearFront = {
+    gear1: null, //扇叶
+    gear2: null, //扇叶
+    gear1Direction: -1,
+    gear2Direction: 1,
+    gearFrameId: undefined,
+    gearRotateFactor: 0.5,
+    endGearRotateFactor: 3,
+  };
+  gearBack = {
+    gear1: null, //扇叶
+    gear2: null, //扇叶
+    gear1Direction: -1, // 扇叶转动方向
+    gear2Direction: 1, // 扇叶转动方向
+    gearFrameId: undefined,
+    gearRotateFactor: 0.5, // 扇叶转动因素
+    endGearRotateFactor: 3, // 扇叶最终转动速度因素
+  };
+  oldMaterial: THREE.Material = new THREE.MeshStandardMaterial();
+  // smoke;
+  frontSmoke: Smoke | null = null; // 前面风流对象
+  backSmoke: Smoke | null = null; // 后面风流对象
+  player1; // 视频播放器
+  playerStartClickTime1 = new Date().getTime();
+  frontWindowGroup;
+  backWindowGroup;
+  windowAngle = 0;
+  fbmAnimationClip: THREE.AnimationClip | null = null;
+  fbmMixers: THREE.AnimationMixer | null = null;
+  fbmOpenAction: THREE.AnimationAction | null = null;
+
+  constructor(model, playerVal1) {
+    this.model = model;
+    this.player1 = playerVal1;
+  }
+  // 添加 cssObject
+  addCssText() {
+    if (!this.group) {
+      return;
+    }
+    const ztfjGroup = this.group.getObjectByName('ztfj');
+
+    if (!this.group.getObjectByName('monitorText1')) {
+      const worldPosition = new THREE.Vector3();
+      ztfjGroup?.getObjectByName('FengJiWaiKe_1')?.getWorldPosition(worldPosition);
+      const element = document.getElementById('inputBox') as HTMLElement;
+      const mainCSS3D = new CSS3DObject(element);
+      mainCSS3D.name = 'monitorText1';
+      mainCSS3D.scale.set(0.09, 0.09, 0.09);
+      mainCSS3D.position.set(worldPosition.x + 34, worldPosition.y - 5, worldPosition.z - 35);
+      mainCSS3D.lookAt(worldPosition.x + 34, worldPosition.y + 5, worldPosition.z + 2);
+      this.group.add(mainCSS3D);
+    }
+    if (!this.group.getObjectByName('monitorText2')) {
+      const worldPosition = new THREE.Vector3();
+      ztfjGroup?.getObjectByName('FengJiWaiKe_2')?.getWorldPosition(worldPosition);
+      const element = document.getElementById('inputBox1') as HTMLElement;
+      const mainCSS3D = new CSS3DObject(element);
+      mainCSS3D.name = 'monitorText2';
+      mainCSS3D.scale.set(0.09, 0.09, 0.09);
+      mainCSS3D.position.set(worldPosition.x + 34, worldPosition.y - 5, worldPosition.z - 20);
+      mainCSS3D.lookAt(worldPosition.x + 34, worldPosition.y + 5, worldPosition.z + 2);
+      this.group.add(mainCSS3D);
+    }
+
+    if (!this.group.getObjectByName('monitorText3')) {
+      const worldPosition = new THREE.Vector3();
+      const fbmGroup = this.group?.getObjectByName('fbm') as THREE.Group;
+      if (fbmGroup) {
+        fbmGroup?.getObjectByName('Box022')?.getWorldPosition(worldPosition);
+        const element = document.getElementById('fbm') as HTMLElement;
+        if (element) {
+          const mainCSS3D = new CSS3DObject(element);
+          mainCSS3D.name = 'monitorText3';
+          mainCSS3D.scale.set(0.07, 0.07, 0.07);
+          mainCSS3D.position.set(worldPosition.x + 20, worldPosition.y - 8, worldPosition.z - 20);
+          mainCSS3D.lookAt(worldPosition.x + 20, worldPosition.y - 0, worldPosition.z + 2);
+          this.group.add(mainCSS3D);
+        }
+      }
+    }
+  }
+
+  addEcharts() {
+    const echartsBox = document.getElementById('fan-echarts');
+    if (echartsBox) {
+      const canvasObj = echartsBox.getElementsByTagName('canvas')[0];
+      // 将canvas 纹理转换为材质
+      const echartsMap = new THREE.CanvasTexture(canvasObj); // 关键一步
+      const echartsMaterial = new THREE.MeshBasicMaterial({
+        map: echartsMap, // 设置纹理贴图
+        transparent: true,
+        side: THREE.FrontSide, // 这里是双面渲染的意思
+      });
+      echartsMaterial.blending = THREE.CustomBlending;
+      const monitorPlane = this.group?.getObjectByName('monitorEcharts');
+      if (monitorPlane) {
+        monitorPlane.material = echartsMaterial;
+      } else {
+        const planeGeometry = new THREE.PlaneGeometry(17.6, 9.9); // 平面3维几何体PlaneGeometry
+        const planeMesh = new THREE.Mesh(planeGeometry, echartsMaterial);
+        planeMesh.name = 'monitorEcharts';
+        planeMesh.scale.set(1, 1, 1);
+        planeMesh.position.set(-47.38, 13.227, -21.79);
+        this.group?.add(planeMesh);
+      }
+    }
+  }
+
+  initAnimation() {}
+
+  startAnimation() {}
+
+  /* 更新动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.fbmMixers) this.fbmMixers?.update(1 / 25);
+  }
+
+  /* 点击风窗,风窗全屏 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    // 判断是否点击到视频
+    intersects.find((intersect) => {
+      const mesh = intersect.object;
+      if (mesh.name === 'player1') {
+        if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+          // 双击,视频放大
+          if (this.player1) {
+            this.player1.requestFullscreen();
+          }
+        }
+        this.playerStartClickTime1 = new Date().getTime();
+        return true;
+      }
+      return false;
+    });
+  }
+
+  mouseUpModel() {}
+
+  async setDeviceFrequency(deviceType, state, frequencyVal?) {
+    // 调节频率
+    if (frequencyVal) {
+      this.resetSmokeParam(deviceType, frequencyVal, 0);
+    }
+    // this.openOrCloseValve(deviceType, state, 0);
+    this.startGearAnimation(deviceType, state, '', 0);
+    if (deviceType === 'front') {
+      this.frontSmoke?.startSmoke();
+    } else {
+      this.backSmoke?.startSmoke();
+    }
+    setTimeout(() => {
+      this.lookMotor(deviceType, state, 10);
+    }, 2000);
+  }
+
+  async openDevice(deviceType, smokeDirection, frequencyVal, duration?) {
+    if (smokeDirection) {
+      this.setSmokeDirection(deviceType, smokeDirection);
+    }
+    let smoke;
+    if (deviceType === 'front') {
+      smoke = this.frontSmoke;
+    } else {
+      smoke = this.backSmoke;
+    }
+    if (!smoke.frameId) {
+      await this.lookMotor(deviceType, 'open', duration);
+      // await this.openOrCloseValve(deviceType, 'open', duration);
+      this.startGearAnimation(deviceType, 'open', smokeDirection, frequencyVal, duration);
+      smoke.startSmoke(duration);
+    }
+  }
+
+  async closeDevice(deviceType, flag = true) {
+    let smoke;
+    if (deviceType === 'front') {
+      smoke = this.frontSmoke;
+    } else if (deviceType === 'back') {
+      smoke = this.backSmoke;
+    }
+    if (smoke && smoke.frameId) {
+      // console.log('风机关闭', deviceType);
+      if (flag) {
+        smoke.stopSmoke();
+        // await this.openOrCloseValve(deviceType, 'close');
+        this.startGearAnimation(deviceType, 'close', '', null);
+        await this.lookMotor(deviceType, 'close');
+      } else {
+        smoke.stopSmoke(0);
+        // await this.openOrCloseValve(deviceType, 'close', 0);
+        this.startGearAnimation(deviceType, 'close', '', null, 0);
+        await this.lookMotor(deviceType, 'close', 0);
+      }
+    }
+  }
+
+  async setSmokeDirection(deviceType, smokeDirection) {
+    const windowPositivePath = [
+      {
+        path0: new THREE.Vector3(4.441, 20.267, 3.614),
+        path1: new THREE.Vector3(5.041, 6.806, 3.614),
+        isSpread: true,
+        spreadDirection: -1, //
+      },
+      {
+        path0: new THREE.Vector3(7.441, 0.806, 3.614),
+        path1: new THREE.Vector3(41.583, 1.485, 3.614),
+        isSpread: false,
+        spreadDirection: 0, //
+      },
+      {
+        path0: new THREE.Vector3(41.583, 1.485, 3.614),
+        path1: new THREE.Vector3(42.741, 5.364, 3.614),
+        isSpread: false,
+        spreadDirection: 0,
+      },
+      {
+        path0: new THREE.Vector3(42.741, 5.364, 3.614),
+        path1: new THREE.Vector3(44.741, 17.267, 3.614),
+        isSpread: true,
+        spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)
+      },
+    ];
+    const windowInversePath = [
+      {
+        path0: new THREE.Vector3(44.741, 17.267, 3.614),
+        path1: new THREE.Vector3(42.741, 5.364, 3.614),
+        isSpread: true,
+        spreadDirection: -1, //
+      },
+      {
+        path0: new THREE.Vector3(42.741, 5.364, 3.614),
+        path1: new THREE.Vector3(41.583, 1.485, 3.614),
+        isSpread: false,
+        spreadDirection: 0, //
+      },
+      {
+        path0: new THREE.Vector3(41.583, 1.485, 3.614),
+        path1: new THREE.Vector3(7.441, 0.806, 3.614),
+        isSpread: false,
+        spreadDirection: 0, // 1是由小变大,-1是由大变小
+      },
+      {
+        path0: new THREE.Vector3(4.441, 17.267, 3.614),
+        path1: new THREE.Vector3(5.041, 6.806, 3.614),
+        isSpread: true,
+        spreadDirection: 1, //
+      },
+    ];
+    const tubPositivePath = [
+      {
+        path0: new THREE.Vector3(7.441, 0.806, 3.614),
+        path1: new THREE.Vector3(44.583, 1.485, 3.614),
+        isSpread: false,
+        spreadDirection: 0, //
+      },
+      {
+        path0: new THREE.Vector3(44.583, 1.485, 3.614),
+        path1: new THREE.Vector3(45.741, 5.364, 3.614),
+        isSpread: false,
+        spreadDirection: 0,
+      },
+      {
+        path0: new THREE.Vector3(45.741, 5.364, 3.614),
+        path1: new THREE.Vector3(47.741, 17.267, 3.614),
+        isSpread: true,
+        spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)
+      },
+    ];
+    const tubInversePath = [
+      {
+        path0: new THREE.Vector3(47.741, 17.267, 3.614),
+        path1: new THREE.Vector3(45.741, 5.364, 3.614),
+        isSpread: true,
+        spreadDirection: -1, //
+      },
+      {
+        path0: new THREE.Vector3(45.741, 5.364, 3.614),
+        path1: new THREE.Vector3(44.583, 1.485, 3.614),
+        isSpread: false,
+        spreadDirection: 0, //
+      },
+      {
+        path0: new THREE.Vector3(44.583, 1.485, 3.614),
+        path1: new THREE.Vector3(7.441, 0.806, 3.614),
+        isSpread: false,
+        spreadDirection: 0, // 1是由小变大,-1是由大变小
+      },
+    ];
+    let smoke;
+    if (deviceType === 'front') {
+      smoke = this.frontSmoke;
+    } else if (deviceType === 'back') {
+      smoke = this.backSmoke;
+    }
+    switch (smokeDirection) {
+      case 'tubPositivePath': // 风筒正
+        smoke.setPath(tubPositivePath);
+        break;
+      case 'tubInversePath': // 风筒反
+        smoke.setPath(tubInversePath);
+        break;
+      case 'windowPositivePath': // 风窗正
+        smoke.setPath(windowPositivePath);
+        break;
+      case 'windowInversePath': // 风窗反
+        smoke.setPath(windowInversePath);
+        break;
+    }
+  }
+
+  /* 播放气流动画 */
+  /**
+   *
+   * @param controlType // 设备控制类型
+   * @param deviceType //前后风机
+   * @param frequencyVal // 风机运行频率
+   * @param state // 打开、关闭状态
+   */
+  async playSmoke(controlType, deviceType, frequencyVal, state, smokeDirection) {
+    if (frequencyVal) {
+      this.resetSmokeParam(deviceType, frequencyVal);
+    }
+    if (controlType === 'startSmoke') {
+      if (state === 'stop') {
+        await this.closeDevice(deviceType);
+      } else {
+        // 开启时需要设置方向
+        await this.openDevice(deviceType, smokeDirection, frequencyVal);
+      }
+    } else if (controlType === 'changeDirection') {
+      // 改变扇叶转动方向、反风
+      this.startGearAnimation(deviceType, 'changeDirection', smokeDirection, frequencyVal);
+      let smoke;
+      if (deviceType === 'front') {
+        smoke = this.frontSmoke;
+      } else {
+        smoke = this.backSmoke;
+      }
+      if (smoke && smoke.frameId) {
+        await smoke.stopSmoke();
+        await this.setSmokeDirection(deviceType, smokeDirection);
+        smoke.startSmoke();
+      }
+    } else if (controlType === 'frequency') {
+      this.startGearAnimation(deviceType, 'frequency', smokeDirection, frequencyVal);
+    } else if (controlType === 'initiatePlay') {
+      this.openDevice(deviceType, smokeDirection, frequencyVal, 0);
+    } else if (controlType === 'changeSmoke') {
+      //
+    }
+  }
+
+  stopSmoke() {
+    this.closeDevice('front', false);
+    this.closeDevice('back', false);
+  }
+
+  /* 打开或关闭蝶阀 */
+  openOrCloseValve(deviceType, flag, duration = 3) {
+    const ztfjGroup = this.group?.getObjectByName('ztfj')?.getObjectByName('WaiKe');
+    return new Promise((resolve) => {
+      let diefa;
+      if (deviceType == 'front') {
+        diefa = ztfjGroup?.getObjectByName('Cylinder1206') as THREE.Mesh;
+      } else {
+        diefa = ztfjGroup?.getObjectByName('Cylinder1041') as THREE.Mesh;
+      }
+      let rotationY;
+      if (flag == 'open') {
+        rotationY = 0;
+      } else {
+        rotationY = Math.PI / 2;
+      }
+      if (diefa) {
+        gsap.to(diefa.rotation, {
+          y: rotationY,
+          duration: duration,
+          ease: 'none',
+          onComplete: function () {
+            resolve(null);
+          },
+        });
+      }
+    });
+  }
+
+  /* 风流调频, 范围1-50 */
+  // opacityFactor (0.4 300)
+  // life 最小 300, 最大 50
+  // speedFactor 最大0, 最小100
+  resetSmokeParam(deviceType, frequency, duration = 5) {
+    if (frequency < 1) frequency = 1;
+    if (frequency > 50) frequency = 50;
+    let smoke;
+    if (deviceType === 'front') {
+      smoke = this.frontSmoke;
+    } else {
+      smoke = this.backSmoke;
+    }
+    const opacityFactor = (frequency / 50) * 0.8;
+    duration = (Number(Math.abs(smoke.opacityFactor - opacityFactor).toFixed(1)) / 0.8) * 5;
+    const life = (-250 / 50) * frequency + 300;
+    gsap.to(smoke, {
+      opacityFactor: opacityFactor,
+      life: life,
+      duration: duration,
+      ease: 'easeInCirc',
+      overwrite: true,
+    });
+  }
+
+  /* 显示电机 */
+  lookMotor(deviceType, flag, duration = 5) {
+    return new Promise((resolve) => {
+      const ztfjGroup = this.group?.getObjectByName('ztfj');
+      let fengJiWaiKeGoup1, fengJiWaiKeGoup2, mesh, mesh1, mesh2, motorGroup;
+
+      fengJiWaiKeGoup1 = ztfjGroup?.getObjectByName('FengJiWaiKe_1'); //前
+      fengJiWaiKeGoup2 = ztfjGroup?.getObjectByName('FengJiWaiKe_2'); //前
+
+      mesh1 = fengJiWaiKeGoup1?.getObjectByName('transparent_shell02'); //前
+      mesh2 = fengJiWaiKeGoup2?.getObjectByName('transparent_shell00'); //后
+      if (deviceType == 'front') {
+        mesh = mesh1;
+        motorGroup = this.motorGroup2;
+      } else {
+        mesh = mesh2;
+        motorGroup = this.motorGroup1;
+      }
+      if (mesh && motorGroup) {
+        if (flag == 'open') {
+          mesh.material.depthWrite = false;
+          mesh.material.depthTest = false;
+
+          motorGroup.visible = true;
+          gsap.to(mesh.material, {
+            opacity: 0.1,
+            duration: duration,
+            overwrite: true,
+            onComplete: function () {
+              // mesh.material.color = '#000';
+              resolve(null);
+            },
+          });
+        } else {
+          const opacity = mesh.material.opacity;
+          Object.assign(mesh.material, this.oldMaterial, { opacity: opacity });
+          mesh.material.depthWrite = true;
+          mesh.material.depthTest = true;
+          gsap.to(mesh.material, {
+            opacity: 1,
+            duration: 1,
+            overwrite: true,
+            onComplete: function () {
+              resolve(null);
+            },
+          });
+        }
+      }
+    });
+  }
+
+  /* 齿轮转动动画 1 - 50  最大3 */
+  startGearAnimation(deviceType, flag, smokeDirection, frequencyVal, duration = 8) {
+    console.log(deviceType, flag);
+    debugger;
+    let gearObj, gearDirection;
+    if (deviceType === 'front') {
+      gearObj = this.gearFront;
+    } else {
+      gearObj = this.gearBack;
+    }
+    if (smokeDirection === 'tubPositivePath') {
+      gearDirection = 1;
+    } else if (smokeDirection === 'tubInversePath') {
+      gearDirection = -1;
+    }
+    if (frequencyVal) {
+      const endGearRotateFactor = (3 / 50) * frequencyVal;
+      duration = (8 / 3) * Math.abs(gearObj.endGearRotateFactor - endGearRotateFactor);
+      gearObj.endGearRotateFactor = endGearRotateFactor;
+    }
+
+    const gearAnimation = () => {
+      gsap.to(gearObj, {
+        gearRotateFactor: gearObj.endGearRotateFactor,
+        duration: duration,
+        ease: 'easeInCubic',
+        repeat: 0,
+        overwrite: true,
+      });
+
+      const clock = new THREE.Clock(); // 时钟
+      const h = () => {
+        if (gearObj.gear1 && gearObj.gear2) {
+          gearObj.gearFrameId = requestAnimationFrame(h);
+
+          const dt = clock.getDelta();
+          gearObj.gear1.rotation.x += dt * gearObj.gearRotateFactor * gearObj.gear1Direction;
+          gearObj.gear2.rotation.x += dt * gearObj.gearRotateFactor * gearObj.gear2Direction;
+        }
+      };
+      h();
+    };
+    if (flag === 'changeDirection') {
+      if (gearDirection == -1 * gearObj.gear1Direction) {
+        // 齿轮正在转,需要停止后再反方向转
+        gsap.to(gearObj, {
+          gearRotateFactor: 0,
+          duration: duration,
+          ease: 'easeInCubic',
+          repeat: 0,
+          onComplete: function () {
+            window.cancelAnimationFrame(gearObj.gearFrameId);
+            gearObj.gearFrameId = undefined;
+            gearObj.gear1Direction = -1 * gearObj.gear1Direction;
+            gearObj.gear2Direction = -1 * gearObj.gear2Direction;
+            gearAnimation();
+          },
+        });
+      }
+    } else if (flag === 'open') {
+      gearObj.gear1Direction = gearDirection;
+      gearObj.gear2Direction = -1 * gearDirection;
+      gearAnimation();
+    } else if (flag === 'close') {
+      gsap.to(gearObj, {
+        gearRotateFactor: 0,
+        duration: duration,
+        ease: 'easeInCubic',
+        repeat: 0,
+        overwrite: true,
+        onComplete: function () {
+          window.cancelAnimationFrame(gearObj.gearFrameId);
+          gearObj.gearFrameId = undefined;
+        },
+      });
+    } else if (flag === 'frequency') {
+      gsap.to(gearObj, {
+        gearRotateFactor: gearObj.endGearRotateFactor,
+        duration: duration,
+        ease: 'easeInCubic',
+        repeat: 0,
+        overwrite: true,
+      });
+    }
+  }
+
+  /* 初始化口上面的气体 */
+  initSmokeMass() {
+    if (!this.frontSmoke) {
+      this.frontSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.38, 1.8, 100);
+    }
+    if (!this.backSmoke) {
+      this.backSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.38, 1.8, 100);
+    }
+  }
+
+  /* 设置气流位置 */
+  async setSmokePosition() {
+    if (this.frontSmoke) {
+      await this.frontSmoke.setPoints();
+      this.frontSmoke.points.name = 'frontSmoke';
+      this.group?.add(this.frontSmoke.points);
+      // this.frontSmoke.points.position.set(-2.51, 2.51, 8.25);
+      this.frontSmoke.points.position.set(3.18, 4.43, 2.31);
+    }
+    if (this.backSmoke) {
+      await this.backSmoke.setPoints();
+      this.backSmoke.points.name = 'backSmoke';
+      this.group?.add(this.backSmoke.points);
+      // this.backSmoke.points.position.set(-2.2, 3.13, -7.8);
+      this.backSmoke.points.position.set(3.18, 4.36, -13.99);
+    }
+  }
+
+  /** 初始化电机 */
+  async initMotor() {
+    // 前电机
+    const motorGltf1 = await this.model.setGLTFModel('dj1');
+    this.motorGroup1 = motorGltf1[0] as THREE.Group;
+    this.motorGroup1?.position.set(10, 1, -6);
+    // this.motorGroup1.visible = false;
+    this.motorGroup1.traverse((item) => {
+      if (item instanceof THREE.Object3D) {
+        item.renderOrder = -1;
+        if (item.name === 'fan_blade003') {
+          // @ts-ignore
+          this.gearBack.gear1 = item as THREE.Group;
+        } else if (item.name === 'fan_blade005') {
+          // @ts-ignore
+          this.gearBack.gear2 = item as THREE.Group;
+        }
+      }
+    });
+    this.motorGroup1.renderOrder = -1;
+    this.group?.add(this.motorGroup1);
+
+    // 后电机
+    const motorGltf2 = await this.model.setGLTFModel('dj2');
+    this.motorGroup2 = motorGltf2[0] as THREE.Group;
+    this.motorGroup2?.position.set(10, 1, -6);
+    // this.motorGroup2.visible = false;
+    this.motorGroup2.traverse((item) => {
+      if (item instanceof THREE.Object3D) {
+        item.renderOrder = -1;
+        if (item.name === 'fan_blade007') {
+          // @ts-ignore
+          this.gearFront.gear1 = item as THREE.Group;
+        } else if (item.name === 'fan_blade006') {
+          // @ts-ignore
+          this.gearFront.gear2 = item as THREE.Group;
+        }
+      }
+    });
+    this.motorGroup2.renderOrder = -1;
+    this.group?.add(this.motorGroup2);
+  }
+
+  openOrCloseWindow(deviceType, flag) {
+    const _this = this;
+    let endAngle = 0,
+      windowGroup;
+    if (deviceType === 'front') {
+      windowGroup = this.frontWindowGroup;
+    }
+    if (deviceType === 'back') {
+      windowGroup = this.backWindowGroup;
+    }
+    if (flag == 'openWindow') {
+      // 打开风窗
+      endAngle = 1;
+    } else {
+      // 关闭风窗
+      endAngle = 0;
+    }
+    if (windowGroup)
+      gsap.to(this, {
+        windowAngle: endAngle,
+        duration: Math.abs(endAngle - this.windowAngle) * 10,
+        ease: 'none',
+        onUpdate: function () {
+          windowGroup.children.forEach((mesh) => {
+            mesh.rotation.z = _this.windowAngle;
+          });
+        },
+      });
+  }
+
+  playAnimation(flag, duration?) {}
+
+  mountedThree() {
+    this.group = new THREE.Group();
+    debugger;
+    return new Promise(async (resolve) => {
+      this.model.setGLTFModel(['ztfj-xj']).then(async (gltf) => {
+        const ztfjModal = gltf[0].children[0];
+        ztfjModal.name = 'ztfj';
+        ztfjModal.position.set(4.64, 4.11, 1.52);
+        this.group?.add(gltf[0].children[0]);
+        // this.group?.position.set(4.77, 3.63, 0.63);
+        this.group?.position.set(-0.44, 19.88, 22.37);
+        this.initSmokeMass();
+        await this.setSmokePosition();
+
+        const ztfjGroup = this.group?.getObjectByName('ztfj');
+        const fengJiWaiKeGoup1 = ztfjGroup?.getObjectByName('FengJiWaiKe_1'); //前
+        const mesh = fengJiWaiKeGoup1?.getObjectByName('transparent_shell02'); //前
+        if (mesh && mesh.material) this.oldMaterial = mesh.material as THREE.MeshStandardMaterial;
+        await this.initMotor();
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.frontSmoke.clearSmoke();
+    this.backSmoke.clearSmoke();
+
+    this.model.clearGroup(this.motorGroup1);
+    this.model.clearGroup(this.motorGroup2);
+    this.model.clearGroup(this.group);
+
+    this.motorGroup1 = undefined;
+    this.motorGroup2 = undefined;
+
+    this.gearFront.gear1 = undefined;
+    this.gearFront.gear2 = undefined;
+
+    this.gearBack.gear1 = undefined;
+    this.gearBack.gear2 = undefined;
+
+    this.frontSmoke = undefined;
+    this.backSmoke = undefined;
+
+    this.model = undefined;
+    this.group = undefined;
+  }
+}
+
+export default mainXjWindRect;