Pārlūkot izejas kodu

[Feat 0000] 主通风机SVG模型动画开发

houzekong 2 dienas atpakaļ
vecāks
revīzija
f1302dec4c

+ 45 - 27
src/hooks/vent/useSvgAnimation.ts

@@ -6,7 +6,7 @@ import _ from 'lodash';
  *
  * 备注:一个元素的动画仅有两种状态,正常播放、倒放;例如:`triggerAnimation(id1, false)`代表触发id1对应的动画,false代表触发正常播放的动画
  */
-export function useSvgAnimation(elementInfo: Map<string, { key: string; transforms: string[] }>) {
+export function useSvgAnimation(elementInfo: Map<string, { key: string; transforms?: string[]; opacity?: string[] }>) {
   /** 所有动画元素 */
   const animationElements = new Map<string, HTMLElement>();
   /** 管理节点是否处于初始状态 */
@@ -19,10 +19,17 @@ export function useSvgAnimation(elementInfo: Map<string, { key: string; transfor
    *
    * @param id 标识符号(可以在页面中使用元素选择器选择具体元素后查询其id),可以传数组
    * @param reverse 是否需要反向执行动画,如果id传了数组该参数可以传数组以一一匹配,默认为false
-   * @param duration 动画持续时长,越长动画执行的越慢
-   * @param progress 指定动画执行的进度,默认为1,即动画执行到100%,该数字范围为0-1
+   * @param config.duration 动画持续时长,越长动画执行的越慢
+   * @param config.progress 指定动画执行的进度,默认为1,即动画执行到100%,该数字范围为0-1
    */
-  function triggerAnimation(id: string | string[], reverse: boolean | boolean[] = false, duration = 3000, progress = 1) {
+  function triggerAnimation(
+    id: string | string[],
+    reverse: boolean | boolean[] = false,
+    config: {
+      duration?: number;
+      progress?: number;
+    } = {}
+  ) {
     const idArray = typeof id === 'string' ? [id] : id;
     const reverseArray = typeof reverse === 'boolean' ? idArray.map(() => reverse) : reverse;
 
@@ -36,54 +43,65 @@ export function useSvgAnimation(elementInfo: Map<string, { key: string; transfor
       // 不指定反向播放且group处于初始状态时播放正常动画
       if (!reverse && unchanged) {
         animationManager.value[id] = false;
-        animateByKey(id, true, duration, progress);
+        animateByKey(id, false, config);
         return;
       }
       if (reverse && !unchanged) {
         animationManager.value[id] = true;
-        animateByKey(id, false, duration, progress);
+        animateByKey(id, true, config);
         return;
       }
     });
   }
 
   // 直接控制动画的方法
-  const animateElement = (elementId: string, toEnd: boolean, duration = 3000, progress = 1) => {
+  const animateElement = (
+    elementId: string,
+    reverse: boolean = false,
+    config: {
+      duration?: number;
+      progress?: number;
+    } = {}
+  ) => {
+    const { duration = 3000, progress = 1 } = config;
     const el = animationElements.get(elementId);
     const info = elementInfo.get(elementId);
-    progress = _.clamp(progress, 0, 1);
+    const percentage = _.clamp(progress, 0, 1);
 
-    if (el && info && info.transforms.length > 1) {
-      const endTransform = info.transforms[Math.floor((info.transforms.length - 1) * progress)];
-      const startTransform = info.transforms[Math.floor((info.transforms.length - 1) * (1 - progress))];
+    if (!el || !info) return;
+
+    // 应用动画
+    if (info.transforms && info.transforms.length > 1) {
+      const endTransform = info.transforms[Math.floor((info.transforms.length - 1) * percentage)];
+      const startTransform = info.transforms[Math.floor((info.transforms.length - 1) * (1 - percentage))];
       el.style.transition = `transform ${duration}ms`;
-      el.setAttribute('transform', toEnd ? endTransform : startTransform);
+      el.setAttribute('transform', reverse ? startTransform : endTransform);
+    }
+    if (info.opacity && info.opacity.length > 1) {
+      const endOpacity = info.opacity[Math.floor((info.opacity.length - 1) * percentage)];
+      const startOpacity = info.opacity[Math.floor((info.opacity.length - 1) * (1 - percentage))];
+      el.style.transition = `opacity ${duration}ms`;
+      el.setAttribute('opacity', reverse ? startOpacity : endOpacity);
     }
   };
 
   // 批量控制同一key的所有元素
-  const animateByKey = (key: string, toEnd: boolean, duration = 3000, progress = 1) => {
+  const animateByKey = (
+    key: string,
+    reverse: boolean = false,
+    config: {
+      duration?: number;
+      progress?: number;
+    } = {}
+  ) => {
     animationElements.forEach((__, elementId) => {
       const info = elementInfo.get(elementId);
       if (info && info.key === key) {
-        animateElement(elementId, toEnd, duration, progress);
+        animateElement(elementId, reverse, config);
       }
     });
   };
 
-  // watch(
-  //   () => animationManager,
-  //   () => {
-  //     Object.keys(animationManager).forEach((key) => {
-  //       const unchanged = animationManager[key];
-
-  //       // 找到所有属于这个key的元素
-  //       animateByKey(key, !unchanged);
-  //     });
-  //   },
-  //   { deep: true }
-  // );
-
   return {
     animationElements,
     triggerAnimation,

+ 249 - 0
src/views/vent/monitorManager/mainFanMonitor/components/entryThree.vue

@@ -0,0 +1,249 @@
+<template>
+  <div class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
+    <!-- <a-spin :spinning="loading" /> -->
+    <div
+      id="main3DCSS"
+      class="threejs-Object-CSS"
+      style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 1; top: 0"
+    >
+      <div style="position: relative" v-if="selectData['modalTyoe']">
+        <div class="elementTag" id="inputBox1" v-if="backMonitorIsShow && false">
+          <div class="elementContent elementContent-r">
+            <!-- <div class="element-item"><span class="data-title">风机气压(Pa):</span><span>{{ selectData.DataPa ? selectData.DataPa : '-' }}</span></div> -->
+            <div class="element-item"
+              ><span class="data-title">风机负压(Pa):</span><span>{{ selectData.Fan2FanPre ? selectData.Fan2FanPre : '-' }}</span></div
+            >
+            <div class="element-item"
+              ><span class="data-title">风机风量(m³/s):</span><span>{{ selectData.Fan2m3 ? selectData.Fan2m3 : '-' }}</span></div
+            >
+          </div>
+        </div>
+        <div class="elementTag" id="inputBox" v-if="frontMonitorIsShow && false">
+          <div class="elementContent elementContent-r">
+            <!-- <div class="element-item"><span class="data-title">风机全压(Pa):</span><span>{{ selectData.DataPa ? selectData.DataPa : '-' }}</span></div> -->
+            <div class="element-item"
+              ><span class="data-title">风机负压(Pa):</span><span>{{ selectData.Fan1FanPre ? selectData.Fan1FanPre : '-' }}</span></div
+            >
+            <div class="element-item"
+              ><span class="data-title">风机风量(m³/s):</span><span>{{ selectData.Fan1m3 ? selectData.Fan1m3 : '-' }}</span></div
+            >
+          </div>
+        </div>
+        <div class="elementTag" id="inputBox2" v-if="centerMonitorIsShow && false">
+          <div class="elementContent elementContent-r">
+            <!-- <div class="element-item"><span class="data-title">风机气压(Pa):</span><span>{{ selectData.DataPa ? selectData.DataPa : '-' }}</span></div> -->
+            <div class="element-item"
+              ><span class="data-title">风机负压(Pa):</span><span>{{ selectData.Fan3FanPre ? selectData.Fan3FanPre : '-' }}</span></div
+            >
+            <div class="element-item"
+              ><span class="data-title">风机风量(m³/s):</span><span>{{ selectData.Fan3m3 ? selectData.Fan3m3 : '-' }}</span></div
+            >
+          </div>
+        </div>
+        <!-- 18模拟反风锁井 -->
+        <!-- <div v-if="hasPermission('mainFan:ffsjMonitor')" class="elementTag" id="fbm">
+          <div class="elementContent elementContent-r fbm-box">
+            <div class="fbm-video">
+              <LivePlayer id="main-player2" ref="player2" :videoUrl="flvURL2()" muted live />
+              <div class="vent-flex-row-between vent-margin-t-20">
+                <span class="data-title">风门开启状态:</span>
+                <template v-if="selectData['ExplosionVentOpen'] == 1 && selectData['ExplosionVentClose'] == 0">
+                  <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>开启</span>
+                </template>
+                <template v-else-if="selectData['ExplosionVentOpen'] == 0 && selectData['ExplosionVentClose'] == 1">
+                  <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>关闭</span>
+                </template>
+                <template v-else>
+                  <div class="vent-margin-l-10"
+                    ><span class="signal-round signal-round-warning vent-margin-r-8"></span>防爆门正在运行 或 数据异常</div
+                  >
+                </template>
+              </div>
+              <div class="vent-flex-row-between vent-margin-t-10">
+                <span class="data-title">反风锁紧状态:</span>
+                <template
+                  v-if="
+                    selectData['Lock1Open'] == 1 && selectData['Lock1Close'] == 0 && selectData['Lock2Open'] == 1 && selectData['Lock2Close'] == '0'
+                  "
+                >
+                  <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>锁1开</span>
+                  <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>锁2开</span>
+                </template>
+                <template
+                  v-else-if="
+                    selectData['Lock1Open'] == '0' && selectData['Lock1Close'] == 1 && selectData['Lock2Open'] == '0' && selectData['Lock2Close'] == 1
+                  "
+                >
+                  <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>锁1关</span>
+                  <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>锁2关</span>
+                </template>
+                <template v-else>
+                  <div class="vent-margin-l-10"
+                    ><span class="signal-round signal-round-warning vent-margin-r-8"></span>反风锁紧正在运行 或 数据异常</div
+                  >
+                </template>
+              </div>
+            </div>
+            <div class="fbm-data">
+              <div class="element-item"
+                ><span class="data-title">井口负压(kPa):</span
+                ><span>{{ selectData.Fan1FanPre ? selectData.Fan1FanPre : selectData.Fan2FanPre ? selectData.Fan2FanPre : '-' }}</span></div
+              >
+              <div class="element-item"><span class="data-title">井口正压(kPa):</span><span>0</span></div>
+              <div class="element-item"><span class="data-title">井口温度(℃):</span><span>19.132</span></div>
+              <div class="element-item"><span class="data-title">甲烷浓度(%):</span><span>0.36</span></div>
+              <div class="element-item"><span class="data-title">CO浓度(%):</span><span>0</span></div>
+              <div class="vent-flex-row-between">
+                <span class="data-title">操作方式:</span>
+                <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>远程</span>
+                <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>就地</span>
+              </div>
+            </div>
+          </div>
+        </div> -->
+        <div v-if="hasPermission('mainFan:ffsjMonitor')">
+          <div class="elementContent elementContent-r fbm-box">
+            <div class="fbm-video">
+              <div class="vent-flex-row-between vent-margin-t-20">
+                <span class="data-title">风门开启状态:</span>
+                <template v-if="explosionDoorData['gate_1_kai'] == 1">
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['gate_1_kai'] == 1, 'signal-round-gry': explosionDoorData['gate_1_kai'] == 0 }"
+                    ></span
+                    >门1开启</span
+                  >
+                </template>
+                <template v-else-if="explosionDoorData['gate_2_kai'] == 1">
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['gate_1_kai'] == 1, 'signal-round-gry': explosionDoorData['gate_1_kai'] == 0 }"
+                    ></span
+                    >门2开启</span
+                  >
+                </template>
+                <template v-else>
+                  <div class="vent-margin-l-10"
+                    ><span class="signal-round signal-round-warning vent-margin-r-8"></span>防爆门正在运行 或 数据异常</div
+                  >
+                </template>
+              </div>
+              <div class="vent-flex-row-between vent-margin-t-10">
+                <span class="data-title">反风锁紧状态:</span>
+                <div>
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo1_kai'] == 1, 'signal-round-gry': explosionDoorData['suo1_kai'] == 0 }"
+                    ></span
+                    >锁1开</span
+                  >
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo1_guan'] == 1, 'signal-round-gry': explosionDoorData['suo1_guan'] == 0 }"
+                    ></span
+                    >锁1关</span
+                  >
+                </div>
+                <div>
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo2_kai'] == 1, 'signal-round-gry': explosionDoorData['suo2_kai'] == 0 }"
+                    ></span
+                    >锁1开</span
+                  >
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo2_guan'] == 1, 'signal-round-gry': explosionDoorData['suo2_guan'] == 0 }"
+                    ></span
+                    >锁2关</span
+                  >
+                </div>
+                <div>
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo3_kai'] == 1, 'signal-round-gry': explosionDoorData['suo3_kai'] == 0 }"
+                    ></span
+                    >锁3开</span
+                  >
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo3_guan'] == 1, 'signal-round-gry': explosionDoorData['suo3_guan'] == 0 }"
+                    ></span
+                    >锁3关</span
+                  >
+                </div>
+                <div>
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo4_kai'] == 1, 'signal-round-gry': explosionDoorData['suo4_kai'] == 0 }"
+                    ></span
+                    >锁4开</span
+                  >
+                  <span class="data-title"
+                    ><span
+                      class="signal-round vent-margin-r-8"
+                      :class="{ 'signal-round-blue': explosionDoorData['suo4_guan'] == 1, 'signal-round-gry': explosionDoorData['suo4_guan'] == 0 }"
+                    ></span
+                    >锁4关</span
+                  >
+                </div>
+              </div>
+            </div>
+            <div class="fbm-data">
+              <div class="vent-flex-row-between">
+                <span class="data-title">操作方式:</span>
+                <span class="data-title"
+                  ><span
+                    class="signal-round signal-round-blue vent-margin-r-8"
+                    :class="{ 'signal-round-blue': explosionDoorData['jd_yc'] == 1 }"
+                  ></span
+                  >远程</span
+                >
+                <span class="data-title"
+                  ><span class="signal-round vent-margin-r-8" :class="{ 'signal-round-blue': explosionDoorData['jd_yc'] == 0 }"></span>就地</span
+                >
+              </div>
+              <div class="vent-flex-row-between">
+                <span class="data-title">是否检修:</span>
+                <span class="data-title"
+                  ><span
+                    class="signal-round signal-round-blue vent-margin-r-8"
+                    :class="{ 'signal-round-blue': explosionDoorData['zc_jx'] == 1 }"
+                  ></span
+                  >正常</span
+                >
+                <span class="data-title"
+                  ><span class="signal-round vent-margin-r-8" :class="{ 'signal-round-blue': explosionDoorData['zc_jx'] == 0 }"></span>检修</span
+                >
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div id="main3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
+    <FanEchrats id="fan-echarts" :chartData="selectData" style="position: absolute; z-index: -1" />
+  </div>
+</template>
+<script lang="ts" setup>
+  import { usePermission } from '/@/hooks/web/usePermission';
+
+  defineProps<{
+    loading: boolean;
+    selectData: Record<string, any>;
+    explosionDoorData: Record<string, any>;
+    centerMonitorIsShow: boolean;
+    frontMonitorIsShow: boolean;
+    backMonitorIsShow: boolean;
+  }>();
+  const { hasPermission } = usePermission();
+</script>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 699 - 0
src/views/vent/monitorManager/mainFanMonitor/components/mainFanSVG.vue


+ 18 - 236
src/views/vent/monitorManager/mainFanMonitor/index.vue

@@ -1,238 +1,14 @@
 <template>
-  <div class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
-    <!-- <a-spin :spinning="loading" /> -->
-    <div
-      id="main3DCSS"
-      class="threejs-Object-CSS"
-      style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 1; top: 0"
-    >
-      <div style="position: relative" v-if="selectData['modalTyoe']">
-        <div class="elementTag" id="inputBox1" v-if="backMonitorIsShow && false">
-          <div class="elementContent elementContent-r">
-            <!-- <div class="element-item"><span class="data-title">风机气压(Pa):</span><span>{{ selectData.DataPa ? selectData.DataPa : '-' }}</span></div> -->
-            <div class="element-item"
-              ><span class="data-title">风机负压(Pa):</span><span>{{ selectData.Fan2FanPre ? selectData.Fan2FanPre : '-' }}</span></div
-            >
-            <div class="element-item"
-              ><span class="data-title">风机风量(m³/s):</span><span>{{ selectData.Fan2m3 ? selectData.Fan2m3 : '-' }}</span></div
-            >
-          </div>
-        </div>
-        <div class="elementTag" id="inputBox" v-if="frontMonitorIsShow && false">
-          <div class="elementContent elementContent-r">
-            <!-- <div class="element-item"><span class="data-title">风机全压(Pa):</span><span>{{ selectData.DataPa ? selectData.DataPa : '-' }}</span></div> -->
-            <div class="element-item"
-              ><span class="data-title">风机负压(Pa):</span><span>{{ selectData.Fan1FanPre ? selectData.Fan1FanPre : '-' }}</span></div
-            >
-            <div class="element-item"
-              ><span class="data-title">风机风量(m³/s):</span><span>{{ selectData.Fan1m3 ? selectData.Fan1m3 : '-' }}</span></div
-            >
-          </div>
-        </div>
-        <div class="elementTag" id="inputBox2" v-if="centerMonitorIsShow && false">
-          <div class="elementContent elementContent-r">
-            <!-- <div class="element-item"><span class="data-title">风机气压(Pa):</span><span>{{ selectData.DataPa ? selectData.DataPa : '-' }}</span></div> -->
-            <div class="element-item"
-              ><span class="data-title">风机负压(Pa):</span><span>{{ selectData.Fan3FanPre ? selectData.Fan3FanPre : '-' }}</span></div
-            >
-            <div class="element-item"
-              ><span class="data-title">风机风量(m³/s):</span><span>{{ selectData.Fan3m3 ? selectData.Fan3m3 : '-' }}</span></div
-            >
-          </div>
-        </div>
-        <!-- 18模拟反风锁井 -->
-        <!-- <div v-if="hasPermission('mainFan:ffsjMonitor')" class="elementTag" id="fbm">
-          <div class="elementContent elementContent-r fbm-box">
-            <div class="fbm-video">
-              <LivePlayer id="main-player2" ref="player2" :videoUrl="flvURL2()" muted live />
-              <div class="vent-flex-row-between vent-margin-t-20">
-                <span class="data-title">风门开启状态:</span>
-                <template v-if="selectData['ExplosionVentOpen'] == 1 && selectData['ExplosionVentClose'] == 0">
-                  <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>开启</span>
-                </template>
-                <template v-else-if="selectData['ExplosionVentOpen'] == 0 && selectData['ExplosionVentClose'] == 1">
-                  <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>关闭</span>
-                </template>
-                <template v-else>
-                  <div class="vent-margin-l-10"
-                    ><span class="signal-round signal-round-warning vent-margin-r-8"></span>防爆门正在运行 或 数据异常</div
-                  >
-                </template>
-              </div>
-              <div class="vent-flex-row-between vent-margin-t-10">
-                <span class="data-title">反风锁紧状态:</span>
-                <template
-                  v-if="
-                    selectData['Lock1Open'] == 1 && selectData['Lock1Close'] == 0 && selectData['Lock2Open'] == 1 && selectData['Lock2Close'] == '0'
-                  "
-                >
-                  <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>锁1开</span>
-                  <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>锁2开</span>
-                </template>
-                <template
-                  v-else-if="
-                    selectData['Lock1Open'] == '0' && selectData['Lock1Close'] == 1 && selectData['Lock2Open'] == '0' && selectData['Lock2Close'] == 1
-                  "
-                >
-                  <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>锁1关</span>
-                  <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>锁2关</span>
-                </template>
-                <template v-else>
-                  <div class="vent-margin-l-10"
-                    ><span class="signal-round signal-round-warning vent-margin-r-8"></span>反风锁紧正在运行 或 数据异常</div
-                  >
-                </template>
-              </div>
-            </div>
-            <div class="fbm-data">
-              <div class="element-item"
-                ><span class="data-title">井口负压(kPa):</span
-                ><span>{{ selectData.Fan1FanPre ? selectData.Fan1FanPre : selectData.Fan2FanPre ? selectData.Fan2FanPre : '-' }}</span></div
-              >
-              <div class="element-item"><span class="data-title">井口正压(kPa):</span><span>0</span></div>
-              <div class="element-item"><span class="data-title">井口温度(℃):</span><span>19.132</span></div>
-              <div class="element-item"><span class="data-title">甲烷浓度(%):</span><span>0.36</span></div>
-              <div class="element-item"><span class="data-title">CO浓度(%):</span><span>0</span></div>
-              <div class="vent-flex-row-between">
-                <span class="data-title">操作方式:</span>
-                <span class="data-title"><span class="signal-round signal-round-blue vent-margin-r-8"></span>远程</span>
-                <span class="data-title"><span class="signal-round signal-round-gry vent-margin-r-8"></span>就地</span>
-              </div>
-            </div>
-          </div>
-        </div> -->
-        <div v-if="hasPermission('mainFan:ffsjMonitor')">
-          <div class="elementContent elementContent-r fbm-box">
-            <div class="fbm-video">
-              <div class="vent-flex-row-between vent-margin-t-20">
-                <span class="data-title">风门开启状态:</span>
-                <template v-if="explosionDoorData['gate_1_kai'] == 1">
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['gate_1_kai'] == 1, 'signal-round-gry': explosionDoorData['gate_1_kai'] == 0 }"
-                    ></span
-                    >门1开启</span
-                  >
-                </template>
-                <template v-else-if="explosionDoorData['gate_2_kai'] == 1">
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['gate_1_kai'] == 1, 'signal-round-gry': explosionDoorData['gate_1_kai'] == 0 }"
-                    ></span
-                    >门2开启</span
-                  >
-                </template>
-                <template v-else>
-                  <div class="vent-margin-l-10"
-                    ><span class="signal-round signal-round-warning vent-margin-r-8"></span>防爆门正在运行 或 数据异常</div
-                  >
-                </template>
-              </div>
-              <div class="vent-flex-row-between vent-margin-t-10">
-                <span class="data-title">反风锁紧状态:</span>
-                <div>
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo1_kai'] == 1, 'signal-round-gry': explosionDoorData['suo1_kai'] == 0 }"
-                    ></span
-                    >锁1开</span
-                  >
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo1_guan'] == 1, 'signal-round-gry': explosionDoorData['suo1_guan'] == 0 }"
-                    ></span
-                    >锁1关</span
-                  >
-                </div>
-                <div>
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo2_kai'] == 1, 'signal-round-gry': explosionDoorData['suo2_kai'] == 0 }"
-                    ></span
-                    >锁1开</span
-                  >
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo2_guan'] == 1, 'signal-round-gry': explosionDoorData['suo2_guan'] == 0 }"
-                    ></span
-                    >锁2关</span
-                  >
-                </div>
-                <div>
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo3_kai'] == 1, 'signal-round-gry': explosionDoorData['suo3_kai'] == 0 }"
-                    ></span
-                    >锁3开</span
-                  >
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo3_guan'] == 1, 'signal-round-gry': explosionDoorData['suo3_guan'] == 0 }"
-                    ></span
-                    >锁3关</span
-                  >
-                </div>
-                <div>
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo4_kai'] == 1, 'signal-round-gry': explosionDoorData['suo4_kai'] == 0 }"
-                    ></span
-                    >锁4开</span
-                  >
-                  <span class="data-title"
-                    ><span
-                      class="signal-round vent-margin-r-8"
-                      :class="{ 'signal-round-blue': explosionDoorData['suo4_guan'] == 1, 'signal-round-gry': explosionDoorData['suo4_guan'] == 0 }"
-                    ></span
-                    >锁4关</span
-                  >
-                </div>
-              </div>
-            </div>
-            <div class="fbm-data">
-              <div class="vent-flex-row-between">
-                <span class="data-title">操作方式:</span>
-                <span class="data-title"
-                  ><span
-                    class="signal-round signal-round-blue vent-margin-r-8"
-                    :class="{ 'signal-round-blue': explosionDoorData['jd_yc'] == 1 }"
-                  ></span
-                  >远程</span
-                >
-                <span class="data-title"
-                  ><span class="signal-round vent-margin-r-8" :class="{ 'signal-round-blue': explosionDoorData['jd_yc'] == 0 }"></span>就地</span
-                >
-              </div>
-              <div class="vent-flex-row-between">
-                <span class="data-title">是否检修:</span>
-                <span class="data-title"
-                  ><span
-                    class="signal-round signal-round-blue vent-margin-r-8"
-                    :class="{ 'signal-round-blue': explosionDoorData['zc_jx'] == 1 }"
-                  ></span
-                  >正常</span
-                >
-                <span class="data-title"
-                  ><span class="signal-round vent-margin-r-8" :class="{ 'signal-round-blue': explosionDoorData['zc_jx'] == 0 }"></span>检修</span
-                >
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-    <div id="main3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
-    <FanEchrats id="fan-echarts" :chartData="selectData" style="position: absolute; z-index: -1" />
-  </div>
+  <component
+    ref="modelRef"
+    :loading="loading"
+    :is="modelComponent"
+    :centerMonitorIsShow="centerMonitorIsShow"
+    :frontMonitorIsShow="frontMonitorIsShow"
+    :backMonitorIsShow="backMonitorIsShow"
+    :explosionDoorData="explosionDoorData"
+    :selectData="selectData"
+  />
   <!-- 控制模式 -->
   <div v-if="hasPermission('fan:remote')" class="top-right">
     <div class="control-title">控制模式:</div>
@@ -852,13 +628,13 @@
   import FanDeviceEcharts from '../comment/FanDeviceEcharts.vue';
   import BarAndLine from '../../../../components/chart/BarAndLine.vue';
   import FanEchrats from '/@/views/vent/monitorManager/mainFanMonitor/fanEchrats.vue';
-  import { onBeforeMount, unref, ref, onMounted, inject, onUnmounted, reactive, toRaw, watch, nextTick, defineAsyncComponent } from 'vue';
+  import { onBeforeMount, unref, ref, onMounted, inject, onUnmounted, reactive, toRaw, watch, nextTick, defineAsyncComponent, shallowRef } from 'vue';
   import GroupMonitorTable from '../comment/GroupMonitorTable.vue';
   // // import HistoryTable from '../comment/HistoryTable.vue';
   // import HistoryTable from '../../../vent/comment/history/HistoryTable.vue';
   import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
   import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
-  import { modalTypeArr, fbmControlData, faultDeviceHeader, PointMonitorType } from './main.data';
+  import { modalTypeArr, fbmControlData, faultDeviceHeader, PointMonitorType, getModelComponent } from './main.data';
   import { deviceControlApi } from '/@/api/vent/index';
   import { mountedThree, destroy, addText, setModelType, playAnimate, resetEcharts } from './main.threejs';
   import LivePlayer from '@liveqing/liveplayer-v3';
@@ -902,6 +678,11 @@
     y: 180,
   });
   const modelList = ref<{ text: string; value: string }[]>([]);
+
+  const modelRef = ref();
+  /** 模型对应的组件,根据实际情况分为二维三维 */
+  const modelComponent = shallowRef(getModelComponent(globalConfig.is2DModel));
+
   let modeValue: null | string | number = null;
   const playerRef = ref();
   const isSimulation = true; // 是否模拟状态
@@ -1225,6 +1006,7 @@
 
             addText();
             playAnimate(selectData);
+            modelRef.value?.animate?.(selectData);
           }
 
           if (timer) {

+ 25 - 2
src/views/vent/monitorManager/mainFanMonitor/main.data.ts

@@ -1,10 +1,10 @@
 import { BasicColumn } from '/@/components/Table';
 import { FormSchema } from '/@/components/Table';
-import { rules } from '/@/utils/helper/validator';
-import { reactive } from 'vue';
+import { reactive, defineAsyncComponent } from 'vue';
 import type { EChartsOption } from 'echarts';
 import { useGlobSetting } from '/@/hooks/setting';
 import { cloneDeep } from 'lodash-es';
+import EntryThree from './components/entryThree.vue';
 
 type CtrlLockOpenType = {
   CtrlLockOpen: boolean | undefined;
@@ -2020,3 +2020,26 @@ export const lineFormData = reactive({
   min: null,
   max: null,
 });
+
+const componentsCaches = new Map<string, any>();
+export function getModelComponent(is2DModel: boolean = false, type: string = '') {
+  if (!is2DModel) return EntryThree;
+  // @ts-ignore
+  return defineAsyncComponent(() => {
+    // 为了支持SVG组件切换时不闪烁,先行下载并缓存
+    if (!componentsCaches.has('mainFanSVG')) componentsCaches.set('mainFanSVG', import('./components/mainFanSVG.vue'));
+
+    switch (type) {
+      case 'mainWindRect':
+        return componentsCaches.get('mainFanSVG');
+      case 'mainXjWindRect':
+        return componentsCaches.get('mainFanSVG');
+      case 'mainLjWindRect':
+        return componentsCaches.get('mainFanSVG');
+      case 'mainWindRect3':
+        return componentsCaches.get('mainFanSVG');
+      default:
+        return componentsCaches.get('mainFanSVG');
+    }
+  });
+}

+ 1 - 0
src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts

@@ -536,6 +536,7 @@ export const setModelType = (type) => {
 export const mountedThree = (playerVal1) => {
   return new Promise(async (resolve) => {
     model = new UseThree('#main3D', '#main3DCSS');
+    if (!model || !model.renderer || !model.camera) return;
     model.setEnvMap('test1.hdr');
     model.renderer.toneMappingExposure = 1.0;
     if (model.renderer) {

+ 11 - 4
src/views/vent/monitorManager/windowMonitor/components/windowDualSVG.vue

@@ -2283,7 +2283,9 @@
     if (data.OpenDegree) {
       const progress = _.round(data.OpenDegree / 90, 2);
       if (progress > 0) {
-        triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], false, 3000, progress);
+        triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], false, {
+          progress,
+        });
       } else {
         triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], true);
       }
@@ -2292,7 +2294,9 @@
     if (data.OpenDegree1) {
       const progress = _.round(data.OpenDegree1 / 90, 2);
       if (progress > 0) {
-        triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], false, 3000, progress);
+        triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], false, {
+          progress,
+        });
       } else {
         triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], true);
       }
@@ -2300,7 +2304,9 @@
     if (data.OpenDegree2) {
       const progress = _.round(data.OpenDegree2 / 90, 2);
       if (progress > 0) {
-        triggerAnimation(['Chuang1_shanye_0_Layer0_0_FILL'], false, 3000, progress);
+        triggerAnimation(['Chuang1_shanye_0_Layer0_0_FILL'], false, {
+          progress,
+        });
       } else {
         triggerAnimation(['Chuang1_shanye_0_Layer0_0_FILL'], true);
       }
@@ -2308,7 +2314,8 @@
     // if (data.OpenDegree3) {
     //   const progress = _.round(data.OpenDegree3 / 90, 2);
     //   if (progress > 0) {
-    //     triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], false, 3000, progress);
+    //     triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], false, {
+    // progress});
     //   } else {
     //     triggerAnimation(['Chuang2_shanye_0_Layer0_0_FILL'], true);
     //   }

+ 3 - 1
src/views/vent/monitorManager/windowMonitor/components/windowSVG.vue

@@ -1638,7 +1638,9 @@
     // 当前面积 / 最大面积 = 风窗开度 = 动画进度
     const progress = _.round(parseFloat(data.frontArea) / parseFloat(maxarea), 2);
     if (progress > 0) {
-      triggerAnimation(['Chuang1_shanye_0_Layer0_0_FILL'], false, 3000, progress);
+      triggerAnimation(['Chuang1_shanye_0_Layer0_0_FILL'], false, {
+        progress,
+      });
     } else {
       triggerAnimation(['Chuang1_shanye_0_Layer0_0_FILL'], true);
     }

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels