Просмотр исходного кода

[Mod 0000]防火门监控系统调整文件路径,添加三维动画控制(尚未完成)

wangkeyi 14 часов назад
Родитель
Сommit
22eca77d08

+ 1 - 1
src/views/vent/home/configurable/components/content.vue

@@ -284,7 +284,7 @@ const NitrogenBtnList = defineAsyncComponent(() => import('./preset/nitrogenBtnL
 const cardList = defineAsyncComponent(() => import('./preset/cardList.vue'));
 const generalList = defineAsyncComponent(() => import('./preset/generalList.vue'));
 const GateBoard = defineAsyncComponent(() => import('../belt/components/detail/gateBoard.vue'));
-const fireGateBoard = defineAsyncComponent(() => import('../belt/components/detail/fireGateBoard.vue'));
+const fireGateBoard = defineAsyncComponent(() => import('../firedoor/components/fireDoorBoard.vue'));
 const PersonPositioning = defineAsyncComponent(() => import('./preset/PersonPositioning.vue'));
 // ==================== 新增皮带巷火灾监测组件 ====================
 const SensorStatusPanel = defineAsyncComponent(() => import('./belt/SensorStatusPanel.vue'));

+ 2 - 2
src/views/vent/home/configurable/belt/components/detail/fireGateBoard.vue → src/views/vent/home/configurable/firedoor/components/fireDoorBoard.vue

@@ -75,13 +75,13 @@
 
 <script setup lang="ts">
   import { ref, onMounted, watch, inject } from 'vue';
-  import { getFormattedText } from '../../../hooks/helper';
+  import { getFormattedText } from '../../hooks/helper';
   import pidaihangSVG from '/@/views/vent/monitorManager/fireDoorMonitor/components/pidaihangSVG.vue';
   import { nextTick } from 'process';
   import HandleModal from '/@/views/vent/monitorManager/gateMonitor/modal.vue';
   import { deviceControlApi } from '/@/api/vent/index';
   import { message } from 'ant-design-vue';
-  import { doorControlApi } from '/@/views/vent/home/configurable/configurable.api.fireDoorMonitor';
+  import { doorControlApi } from '/@/views/vent/home/configurable/firedoor/configurable.api.fireDoorMonitor';
   const props = withDefaults(
     defineProps<{
       config: {

+ 0 - 0
src/views/vent/home/configurable/configurable.api.fireDoorMonitor.ts → src/views/vent/home/configurable/firedoor/configurable.api.fireDoorMonitor.ts


+ 4 - 5
src/views/vent/home/configurable/configurable.data.fireDoorMonitor.ts → src/views/vent/home/configurable/firedoor/configurable.data.fireDoorMonitor.ts

@@ -1,5 +1,4 @@
-import type { Config } from '../../deviceManager/configurationTable/types';
-
+import type { Config } from '/@/views/vent/deviceManager/configurationTable/types';
 export const testFireDoorMonitor: Config[] = [
   // ==================== 左侧栏:火灾监测设备状态 ====================
   {
@@ -301,7 +300,7 @@ export const testFireDoorMonitor: Config[] = [
             tilte: '${readData.frontGateOpen.value}',
             items: [
               {
-                label: '防火门状态',
+                label: '防火门状态111',
                 value: '${readData.frontGateOpen.value}',
                 trans: {
                   '1': '打开',
@@ -309,7 +308,7 @@ export const testFireDoorMonitor: Config[] = [
                 },
               },
               {
-                label: '皮带密闭状态',
+                label: '皮带密闭状态111',
                 value: '${readData.MBOpen.value}',
                 trans: {
                   '1': '打开',
@@ -317,7 +316,7 @@ export const testFireDoorMonitor: Config[] = [
                 },
               },
               {
-                label: '网络状态',
+                label: '网络状态111',
                 value: '${netStatus}',
                 trans: {
                   '1': '连接',

+ 23 - 4
src/views/vent/home/configurable/fireDoorMonitor.vue → src/views/vent/home/configurable/firedoor/fireDoorMonitor.vue

@@ -5,7 +5,7 @@
       <div class="main-title">工作面防火门监控系统</div>
     </div>
     <div class="modal-box" id="modalBox">
-      <Three3D :modal-name="modalName" />
+      <Three3D :modal-name="modalName" :monitor-data="modalMonitorData" @success="initModalAnimate" />
     </div>
     <!-- 主体区域 -->
     <div class="border">
@@ -38,17 +38,30 @@
 
 <script setup lang="ts">
   import { onMounted, onUnmounted, ref } from 'vue';
-  import { useInitConfigs, useInitPage } from './hooks/useInit';
+  import { useInitConfigs, useInitPage } from '../hooks/useInit';
   import { testFireDoorMonitor } from './configurable.data.fireDoorMonitor';
   import { manageFireGateHome, manageFireList } from './configurable.api.fireDoorMonitor';
-  import ModuleCommon from './belt/components/ModuleCommon.vue';
+  import ModuleCommon from '../belt/components/ModuleCommon.vue';
   import Three3D from '/@/views/vent/home/configurable/components/three3D.vue';
-
+  import { modalAnimate, destroy } from './threejs/firedoor.threejs';
   // 初始化配置
   const { configs, fetchConfigs } = useInitConfigs();
   const { updateEnhancedConfigs, updateData, data } = useInitPage('工作面防火门监控系统');
   const modalName = ref('pidai-fire-door');
 
+  // 用于传递给 Three.js 的响应式数据
+  const modalMonitorData = ref<any>({});
+  const three3DRef = ref<any>(null);
+  let modalInstance: any = null;
+
+  // 初始化 3D 动画绑定
+  const initModalAnimate = (modal: any) => {
+    modalInstance = modal;
+    // 将响应式数据的 ref 传递给 threejs 逻辑
+    if (modal) {
+      modalAnimate(modal, modalMonitorData);
+    }
+  };
   // 设备场景下拉框选项
   const selectorOptions = ref<{ value: any; label: any }[]>([]);
   const deviceId = ref<string>('');
@@ -101,6 +114,9 @@
         });
       }
       updateData(res);
+      // 更新 3D 视图绑定的数据,触发 watch
+      // 直接赋值给 modalMonitorData.value,保持响应性
+      modalMonitorData.value = res;
     });
   };
 
@@ -111,6 +127,9 @@
 
   onUnmounted(() => {
     clearInterval(interval);
+    if (modalInstance) {
+      destroy(modalInstance);
+    }
   });
 </script>
 <style lang="less" scoped>

+ 170 - 0
src/views/vent/home/configurable/firedoor/threejs/firedoor.threejs.ts

@@ -0,0 +1,170 @@
+import * as THREE from 'three';
+import gsap from 'gsap';
+import { ref, watch, Ref, nextTick } from 'vue';
+
+// 用于存储当前的门状态数据,方便外部调试或扩展
+const gateList = ref<any[]>([]);
+
+/**
+ * 初始化防火门 3D 动画
+ * @param modal Three.js 模态框实例
+ * @param modalMonitorData 响应式数据对象,包含 devMonitorMap.door
+ */
+export async function modalAnimate(modal: any, modalMonitorData: Ref<any, any>) {
+  await nextTick();
+
+  if (!modal || !modal.scene) {
+    console.error('模型加载失败');
+    return;
+  }
+
+  // 获取主模型对象 (假设模型名称结构,根据实际模型调整)
+  // 注意:请确保模型加载完成后调用此函数,或者在 modal.scene 中存在这些对象
+  const fireDoorModal = modal.scene.getObjectByName('pidai')?.getObjectByName('PiDaiHang_1');
+  if (!fireDoorModal) return;
+
+  resetModalParam(modal);
+
+  // 初始化时,强制找到所有门并归零,确保“关闭”状态是物理上的 0,0,0
+  const initFireDoor = fireDoorModal.getObjectByName('men_1');
+  const initBeltCover = fireDoorModal.getObjectByName('gaiban');
+
+  if (initFireDoor) {
+    initFireDoor.rotation.set(0, 0, 0); // 强制归零
+  }
+  if (initBeltCover) {
+    initBeltCover.rotation.set(0, 0, 0); // 强制归零
+  }
+
+  if (!fireDoorModal) {
+    console.warn('模型元素未找到');
+    return;
+  }
+
+  // 重置控制器参数,保持视角稳定
+  resetModalParam(modal);
+
+  /**
+   * 核心动画处理函数
+   * @param doors 门设备数据数组
+   */
+  const handleGateAnimate = (doors: any[]) => {
+    if (!doors || doors.length === 0) return;
+
+    doors.forEach((gateData: any) => {
+      // 查找防火门对象 (men_1, men_2, ...)
+      const fireDoorMesh = fireDoorModal.getObjectByName(`men_1`); //  fallback 测试用
+
+      // 查找皮带密闭对象 (gaiban_1, gaiban_2, ...)
+      const beltCoverMesh = fireDoorModal.getObjectByName(`gaiban`); // fallback 测试用
+
+      // 获取状态值
+      // 注意:数据结构需与 2D 视图一致,通常是 readData.frontGateOpen.value
+      const frontGateOpenVal = gateData['readData']?.['frontGateOpen']?.value;
+      const mbOpenVal = gateData['readData']?.['MBOpen']?.value;
+
+      // 判断状态 (1 或 '1' 为打开)
+      const isFireDoorOpen = frontGateOpenVal == 1;
+      const isBeltCoverOpen = mbOpenVal == 1;
+
+      // 执行防火门动画
+      if (fireDoorMesh) {
+        animateFireDoor(fireDoorMesh, isFireDoorOpen);
+      } else {
+        // console.warn(`Fire door mesh not found for alias: ${posAlias}`);
+      }
+
+      // 执行皮带密闭动画
+      if (beltCoverMesh) {
+        animateBeltCover(beltCoverMesh, isBeltCoverOpen);
+      } else {
+        // console.warn(`Belt cover mesh not found for alias: ${posAlias}`);
+      }
+    });
+  };
+
+  /**
+   * 防火门动画
+   * 关闭: (0, 0, 0)
+   * 开启: (0, 0, 85度) -> 绕 Z 轴旋转
+   */
+  const animateFireDoor = (mesh: THREE.Object3D, isOpen: boolean) => {
+    const targetRotationZ = isOpen ? THREE.MathUtils.degToRad(85) : 0;
+
+    // 使用 GSAP 进行平滑过渡
+    gsap.to(mesh.rotation, {
+      x: 0,
+      y: 0,
+      z: targetRotationZ,
+      duration: 1.5, // 动画时长,可根据需要调整
+      ease: 'power2.inOut',
+      overwrite: true, // 覆盖之前的动画
+    });
+  };
+
+  /**
+   * 皮带密闭动画
+   * 关闭: (0, 0, 0)
+   * 开启: (0, -70度, 0) -> 绕 Y 轴旋转
+   */
+  const animateBeltCover = (mesh: THREE.Object3D, isOpen: boolean) => {
+    const targetRotationY = isOpen ? THREE.MathUtils.degToRad(-70) : 0;
+
+    // 使用 GSAP 进行平滑过渡
+    gsap.to(mesh.rotation, {
+      x: 0,
+      y: targetRotationY,
+      z: 0,
+      duration: 1.5, // 动画时长
+      ease: 'power2.inOut',
+      overwrite: true,
+    });
+  };
+
+  // 监听数据变化,驱动动画
+  watch(
+    modalMonitorData,
+    (newData) => {
+      if (!newData) return;
+
+      // 获取门数据,优先使用 devMonitorMap.door (与 2D 视图一致)
+      const doors = newData.devMonitorMap?.door || [];
+      gateList.value = doors;
+
+      // 执行动画
+      handleGateAnimate(doors);
+    },
+    { immediate: true, deep: true }
+  );
+
+  // 初始化 CSS3D 容器 (如果需要显示 HTML 标签,否则可移除)
+  if (modal.initCSS3Renderer) {
+    modal.initCSS3Renderer('#css3dContainer');
+  }
+
+  // 暴露方法供外部调用(可选)
+  return {
+    gateList,
+    handleGateAnimate,
+  };
+}
+
+function resetModalParam(modal: any) {
+  if (!modal.orbitControls) return;
+
+  // 设置合适的控制器参数
+  modal.orbitControls.rotateSpeed = 0.5;
+  modal.orbitControls.zoomSpeed = 0.6;
+  modal.orbitControls.panSpeed = 0.5;
+  modal.orbitControls.enableDamping = true;
+  modal.orbitControls.dampingFactor = 0.05;
+}
+
+// 清理函数
+export function destroy(modal: any) {
+  gateList.value = [];
+  // 如果有其他需要清理的资源,在这里处理
+  if (modal.canvasContainer) {
+    // 移除事件监听器等
+  }
+}