Преглед изворни кода

Merge branch 'master' of http://182.92.126.35:3000/hrx/mky-vent-base

hongrunxia пре 3 дана
родитељ
комит
ed767cc19d

+ 1 - 1
src/store/constant.ts

@@ -1,2 +1,2 @@
 export const MOCK_LOGIN_UESRNAME = 'autoAdmin';
-export const MOCK_LOGIN_PASSWORD = 'TOdspLGTgSCYCmlXsE1ynw=='; //autoAdmin123;
+export const MOCK_LOGIN_PASSWORD = 'autoAdmin123';

+ 2 - 0
src/views/vent/comment/threejs/ArrowFlow.ts

@@ -23,6 +23,7 @@ export default class ArrowFlow extends THREE.MeshBasicMaterial {
       offsetX = 0,
       /** 0-1 */
       offsetY = 1,
+      rotation = 0,
     } = {}
   ) {
     const t = new THREE.TextureLoader().load(texturePath);
@@ -30,6 +31,7 @@ export default class ArrowFlow extends THREE.MeshBasicMaterial {
     t.wrapT = THREE.RepeatWrapping;
     t.repeat = new THREE.Vector2(repeatX, repeatY);
     t.offset = new THREE.Vector2(offsetX, offsetY);
+    t.rotation = rotation;
     super({ map: t, transparent: true });
     this.texture = t;
     this.repeat = t.repeat;

+ 78 - 78
src/views/vent/home/configurable/components/ModuleCommon.vue

@@ -23,102 +23,102 @@
   </Transition>
 </template>
 <script lang="ts" setup>
-import Header from './header.vue';
-import Content from './content.vue';
-// import ModuleLeft from './original/moduleLeft.vue';
-// import ModuleBottom from './original/moduleBottom.vue';
-import { computed, ref } from 'vue';
-import ventBox1 from '/@/components/vent/ventBox1.vue';
-import { openWindow } from '/@/utils';
-import { getFormattedText } from '../hooks/helper';
-// import { ModuleProps } from '../types';
+  import Header from './header.vue';
+  import Content from './content.vue';
+  // import ModuleLeft from './original/moduleLeft.vue';
+  // import ModuleBottom from './original/moduleBottom.vue';
+  import { computed, ref } from 'vue';
+  import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import { openWindow } from '/@/utils';
+  import { getFormattedText } from '../hooks/helper';
+  // import { ModuleProps } from '../types';
 
-const props = defineProps<{
-  /** 配置的详细模块信息 */
-  moduleData: any;
-  /** 配置的详细样式信息 */
-  showStyle: any;
-  /** 该模块配置中的设备标识符 */
-  deviceType: string;
-  /** api返回的数据 */
-  data: any;
-  moduleName: string;
-  visible: boolean;
-  chartData: any;
-}>();
-defineEmits(['close', 'click']);
+  const props = defineProps<{
+    /** 配置的详细模块信息 */
+    moduleData: any;
+    /** 配置的详细样式信息 */
+    showStyle: any;
+    /** 该模块配置中的设备标识符 */
+    deviceType: string;
+    /** api返回的数据 */
+    data: any;
+    moduleName: string;
+    visible: boolean;
+    chartData?: any;
+  }>();
+  defineEmits(['close', 'click']);
 
-const { header } = props.moduleData;
-const selectedData = ref();
+  const { header } = props.moduleData;
+  const selectedData = ref();
 
-const style = computed(() => {
-  const size = props.showStyle.size;
-  const position = props.showStyle.position;
-  return size + position + 'position: absolute; pointer-events: auto; z-index: 1';
-});
+  const style = computed(() => {
+    const size = props.showStyle.size;
+    const position = props.showStyle.position;
+    return size + position + 'position: absolute; pointer-events: auto; z-index: 1';
+  });
 
-const capitalizedPosition = computed(() => {
-  return props.showStyle.position.includes('left') ? 'Left' : 'Right';
-});
+  const capitalizedPosition = computed(() => {
+    return props.showStyle.position.includes('left') ? 'Left' : 'Right';
+  });
 
-// 根据配置里的定位判断应该使用哪个class
-function getModuleClass({ size, position }) {
-  const [_, width] = size.match(/width:([0-9]+)px/) || [];
-  if (position.includes('bottom') || parseInt(width) > 800) {
-    return 'module-common module-common-longer';
+  // 根据配置里的定位判断应该使用哪个class
+  function getModuleClass({ size, position }) {
+    const [_, width] = size.match(/width:([0-9]+)px/) || [];
+    if (position.includes('bottom') || parseInt(width) > 800) {
+      return 'module-common module-common-longer';
+    }
+    return 'module-common';
   }
-  return 'module-common';
-}
 
-function redirectTo() {
-  const { to } = props.moduleData;
-  if (!to) return;
-  openWindow(getFormattedText(selectedData.value, to));
-}
+  function redirectTo() {
+    const { to } = props.moduleData;
+    if (!to) return;
+    openWindow(getFormattedText(selectedData.value, to));
+  }
 </script>
 <style lang="less" scoped>
-@import '/@/design/theme.less';
+  @import '/@/design/theme.less';
 
-.module-common .box1-center {
-  height: calc(100% - 48px);
-}
+  .module-common .box1-center {
+    height: calc(100% - 48px);
+  }
 
-:deep(.box1-center) {
-  height: calc(100% - 48px);
-}
-:deep(.box1-center > .box-container) {
-  height: 100%;
-  padding: 0 !important;
-  width: 100% !important;
-}
-@{theme-green} {
-  .module-common-longer {
-    :deep(.box1-top) {
-      --image-box1-top: url('/@/assets/images/themify/green/vent/border/box-top.png');
+  :deep(.box1-center) {
+    height: calc(100% - 48px);
+  }
+  :deep(.box1-center > .box-container) {
+    height: 100%;
+    padding: 0 !important;
+    width: 100% !important;
+  }
+  @{theme-green} {
+    .module-common-longer {
+      :deep(.box1-top) {
+        --image-box1-top: url('/@/assets/images/themify/green/vent/border/box-top.png');
+      }
+      :deep(.box1-bottom) {
+        --image-box1-bottom: url('/@/assets/images/themify/green/vent/border/box-bottom.png');
+      }
     }
-    :deep(.box1-bottom) {
-      --image-box1-bottom:  url('/@/assets/images/themify/green/vent/border/box-bottom.png');
+  }
+  @{theme-deepblue} {
+    .module-common-longer {
+      :deep(.box1-top) {
+        --image-box1-top: url('/@/assets/images/themify/deepblue/vent/border/box2-top-long.png');
+      }
+      :deep(.box1-bottom) {
+        --image-box1-bottom: none;
+      }
     }
   }
-}
-@{theme-deepblue} {
   .module-common-longer {
     :deep(.box1-top) {
-      --image-box1-top: url('/@/assets/images/themify/deepblue/vent/border/box2-top-long.png');
+      --image-box1-top: url('/@/assets/images/vent/box-top-bg.png');
+      background-image: var(--image-box1-top);
     }
     :deep(.box1-bottom) {
-      --image-box1-bottom: none;
+      --image-box1-bottom: url('/@/assets/images/vent/box-bottom-bg.png');
+      background-image: var(--image-box1-bottom);
     }
   }
-}
-.module-common-longer {
-  :deep(.box1-top) {
-    --image-box1-top: url('/@/assets/images/vent/box-top-bg.png');
-    background-image: var(--image-box1-top);
-  }
-  :deep(.box1-bottom) {
-    --image-box1-bottom: url('/@/assets/images/vent/box-bottom-bg.png');
-    background-image: var(--image-box1-bottom);
-  }
-}
 </style>

+ 33 - 0
src/views/vent/monitorManager/balancePressMonitor/balancePress.data.ts

@@ -215,3 +215,36 @@ export const settingParam4 = [
     unit: '%',
   },
 ];
+
+export const settingParam5 = [
+  {
+    title: '水柱计压差上限',
+    code: 'waterPressureMax',
+    value: '',
+    unit: 'pa',
+  },
+  {
+    title: '水柱计压差下限',
+    code: 'waterPressureMin',
+    value: '',
+    unit: 'pa',
+  },
+  {
+    title: '压差变化值',
+    code: 'pressureDiffMax',
+    value: '',
+    unit: 'pa',
+  },
+  {
+    title: 'CO上限',
+    code: 'coMaxVal',
+    value: '',
+    unit: '%',
+  },
+  {
+    title: 'CO下限',
+    code: 'coMinVal',
+    value: '',
+    unit: '%',
+  },
+];

+ 351 - 0
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHomeSP.vue

@@ -0,0 +1,351 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box">
+        <Transition enter-active-class="animate__animated  animate__fadeInLeft" leave-active-class="animate__animated  animate__fadeOutLeft">
+          <ventBox1 v-if="showModules">
+            <template #title>
+              <div>均压与低氧参数监测与设置</div>
+            </template>
+            <template #container>
+              <div class="vent-flex-row-between auto-control mt-10px mb-10px">
+                <div class="title">自动调节:</div>
+                <a-radio-group :value="avePressSetting.isAuto" name="radioGroup" @change="changeAvePressState($event, 'isAuto')">
+                  <a-radio :value="false">关闭</a-radio>
+                  <a-radio :value="true">开启</a-radio>
+                </a-radio-group>
+              </div>
+              <div class="vent-flex-row-between auto-control mt-10px mb-10px">
+                <div class="title">调节类型:</div>
+                <a-radio-group :value="avePressSetting.controlType" name="radioGroup" @change="changeAvePressState($event, 'controlType')">
+                  <a-radio value="co">CO</a-radio>
+                  <a-radio value="pressure">压差</a-radio>
+                </a-radio-group>
+              </div>
+              <div>
+                <!-- <div class="divider-line">开始条件</div>
+              <div v-for="(item, index) in settingParam1" class="input-item" :key="index">
+                <div class="title">{{ item.title }}:</div>
+                <a-input-number class="input-value" v-model:value="formData[item.code]" placeholder="" />
+                <div class="unit">{{ item.unit }}</div>
+              </div> -->
+                <div class="divider-line"></div>
+                <div v-for="(item, index) in settingParam5" class="input-item" :key="index">
+                  <div class="title">{{ item.title }}:</div>
+                  <a-input-number class="input-value" v-model:value="avePressSetting[item.code]" placeholder="" :disabled="settingFormDisabled" />
+                  <div class="unit">&nbsp;{{ item.unit }}</div>
+                </div>
+                <!-- <div class="divider-line">结束时间</div>
+              <div v-for="(item, index) in settingParam3" class="input-item" :key="index">
+                <div class="title">{{ item.title }}:</div>
+                <a-input-number class="input-value" v-model:value="formData[item.code]" placeholder="" />
+                <div class="unit">{{ item.unit }}</div>
+              </div> -->
+              </div>
+              <div class="btn-box flex" style="text-align: center">
+                <div class="btn btn1 flex-1" @click="editSettingForm">{{ settingFormDisabled ? '编辑' : '取消' }}</div>
+                <div class="btn btn1 flex-1" @click="submitSettingForm">提交</div>
+              </div>
+            </template>
+          </ventBox1>
+        </Transition>
+      </div>
+
+      <ModuleCommon
+        v-for="(cfg, index) in configs"
+        :key="`svvmbcb${index}`"
+        :show-style="cfg.showStyle"
+        :module-data="cfg.moduleData"
+        :module-name="cfg.moduleName"
+        :device-type="cfg.deviceType"
+        :data="selectData"
+        :visible="showModules"
+      />
+    </div>
+    <PasswordModal z-index="2000" :modal-is-show="modalVisible" modal-title="提交" @handle-ok="handleResolve" @handle-cancel="handleReject" />
+    <UpdatePassword @register="updatePwdRegister" @submit="handleChangePassword" />
+    <!-- <BasicModal title="风门状态监测" :mask="false" :bodyStyle="{ height: '50px' }" style="top: 20px" :show-ok-btn="false" @register="warnRegister2">
+      {{ warnModalText2 }}
+    </BasicModal>
+    <BasicModal
+      title="压差状态监测"
+      :mask="false"
+      :bodyStyle="{ height: '50px' }"
+      centered
+      ok-text="下发联动控制指令"
+      @ok="autoControl"
+      @register="warnRegister1"
+    >
+      {{ warnModalText1 }}
+    </BasicModal>
+    <BasicModal title="局扇状态监测" :mask="false" :bodyStyle="{ height: '50px' }" style="top: 420px" :show-ok-btn="false" @register="warnRegister3">
+      {{ warnModalText3 }}
+    </BasicModal> -->
+
+    <div class="switch-button icon-goto right-10px top-70px" :class="{ 'right-390px': showModules }" @click="showModules = !showModules"></div>
+    <!-- <div v-else class="switch-button icon-goto right-10px top-70px" @click="showModules = true"></div> -->
+  </a-spin>
+</template>
+<script setup lang="ts">
+  import { ref, onMounted, onUnmounted, defineProps } from 'vue';
+  import { mountedThree, destroy, setModelType, updateText, play } from '../balancePress.threejs';
+  import { list } from '../balancePress.api';
+  import ModuleCommon from '../../../home/configurable/components/ModuleCommon.vue';
+  import { useInitConfigs } from '../../../home/configurable/hooks/useInit';
+  import { useGlobSetting } from '/@/hooks/setting';
+  import { settingParam5 } from '../balancePress.data';
+  // import { Modal } from 'ant-design-vue';
+  import ventBox1 from '/@/components/vent/ventBox1.vue';
+  import PasswordModal from '../../comment/components/PasswordModal.vue';
+  import UpdatePassword from '../../comment/components/UpdatePassword.vue';
+  import { useModal } from '/@/components/Modal';
+  // import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
+  // import { getToken } from '/@/utils/auth';
+  // import { useUserStore } from '/@/store/modules/user';
+  import { usePressControl } from '../hooks/useControl';
+  // import dayjs from 'dayjs';
+  // import { Config } from '../../../deviceManager/configurationTable/types';
+
+  const props = defineProps({
+    deviceId: {
+      type: String,
+      require: true,
+    },
+  });
+
+  const { sysOrgCode } = useGlobSetting();
+
+  const loading = ref(false);
+  const showModules = ref(true);
+
+  // 监测数据
+  const selectData = ref();
+
+  // https获取监测数据
+  let timer: any = null;
+  function getMonitor(flag?) {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = setTimeout(
+        async () => {
+          if (props.deviceId) {
+            const data = await getDataSource(props.deviceId);
+            // Object.assign(selectData, data);
+            updateText(selectData);
+            selectData.value = data;
+          }
+          if (timer) {
+            timer = null;
+          }
+          await getMonitor();
+        },
+        flag ? 0 : 1000
+      );
+    }
+  }
+
+  async function getDataSource(systemID) {
+    const res = await list({ devicetype: 'sys', systemID });
+
+    const result = Array.from(res.msgTxt).reduce(
+      (obj: any, e: any) => {
+        obj[e.type] = e;
+
+        // if (true) {
+        if (sysOrgCode === 'sdmtjtswmk') {
+          if (e.type.startsWith('fanlocal')) {
+            obj.fanlocal.datalist.push(...e.datalist);
+          }
+          if (e.type.startsWith('safetymonitor')) {
+            e.datalist.forEach((ele) => {
+              if (ele.strinstallpos.includes('风门')) {
+                obj.gate.datalist.push(ele);
+              } else if (ele.strinstallpos.includes('风窗')) {
+                obj.window.datalist.push(ele);
+              } else if (ele.strinstallpos.includes('工作面')) {
+                obj.work_surface.datalist.push(ele);
+              } else {
+                obj.others.datalist.push(ele);
+              }
+            });
+          }
+        }
+
+        return obj;
+      },
+      {
+        /** 用于归类fanlocal */
+        fanlocal: { datalist: [] },
+        /** 用于归类gate */
+        gate: { datalist: [] },
+        /** 用于归类window */
+        window: { datalist: [] },
+        /** 用于归类work_surface */
+        work_surface: { datalist: [] },
+        others: { datalist: [] },
+      }
+    );
+
+    return result;
+  }
+
+  const {
+    avePressSetting,
+    // avePressLinkage,
+    // gateLinkage,
+    formData,
+    // getAvePress,
+    changePassword,
+    // linkageControl,
+    // settingControl,
+    // autoControl,
+    // cancelControl,
+  } = usePressControl();
+
+  const modalVisible = ref(false);
+
+  const { configs, fetchConfigs } = useInitConfigs();
+
+  const [updatePwdRegister, { closeModal, setModalProps }] = useModal();
+
+  function handleChangePassword(values) {
+    setModalProps({ confirmLoading: true });
+    changePassword(values).finally(() => {
+      setModalProps({ confirmLoading: false });
+      closeModal();
+    });
+  }
+
+  // function changeIsAuto({ target }, id) {
+  //   formData.value.isAuto = target.value;
+  //   modalVisible.value = true;
+  //   resolver = (password) => {
+  //     linkageControl(
+  //       { password, id },
+  //       {
+  //         isAuto: formData.value.isAuto,
+  //       }
+  //     ).finally(() => {
+  //       modalVisible.value = false;
+  //     });
+  //   };
+  // }
+  function changeAvePressState({ target }, __key) {
+    formData.value.temp = target.value;
+    modalVisible.value = true;
+    // resolver = (password) => {
+    //   settingControl(
+    //     { password, id: avePressSetting.value.id },
+    //     {
+    //       [key]: formData.value.temp,
+    //     }
+    //   ).finally(() => {
+    //     modalVisible.value = false;
+    //   });
+    // };
+  }
+
+  // function submitLinkageForm(password) {}
+  function submitSettingForm() {
+    modalVisible.value = true;
+    // resolver = (password) => {
+    //   settingControl({ password, id: avePressSetting.value.id }, avePressSetting.value).finally(() => {
+    //     modalVisible.value = false;
+    //     settingFormDisabled.value = true;
+    //   });
+    // };
+  }
+
+  let resolver: any = null;
+  let rejecter: any = null;
+  function handleResolve(password) {
+    if (resolver) {
+      resolver(password);
+    } else {
+      modalVisible.value = false;
+    }
+    resolver = null;
+    rejecter = null;
+  }
+  function handleReject() {
+    if (rejecter) {
+      rejecter();
+    } else {
+      modalVisible.value = false;
+    }
+    resolver = null;
+    rejecter = null;
+  }
+
+  const settingFormDisabled = ref(true);
+  function editSettingForm() {
+    settingFormDisabled.value = !settingFormDisabled.value;
+    /**  如果取消了编辑模式,那么需要重置表单 */
+    if (settingFormDisabled.value) {
+      // getAvePress();
+    }
+  }
+
+  onMounted(() => {
+    fetchConfigs('balancePressHome');
+    // getAvePress();
+    loading.value = true;
+    mountedThree().then(async () => {
+      if (sysOrgCode === 'jsnyspmy') {
+        await setModelType('balancePressSp'); //balancePressBase
+      } else {
+        await setModelType('balancePressTun'); //balancePressBase
+      }
+      loading.value = false;
+      timer = null;
+      await getMonitor(true);
+      play('startSmoke', 'top', 30, 'open', 0);
+    });
+    // loading.value = false;
+    // timer = null;
+    // getMonitor(true);
+  });
+
+  onUnmounted(() => {
+    destroy();
+    if (timer) {
+      clearTimeout(timer);
+    }
+  });
+</script>
+<style lang="less" scoped>
+  @import '/@/design/vent/modal.less';
+  @import '../../comment/less/workFace.less';
+  @ventSpace: zxm;
+  .monitor-container {
+    margin-top: 60px;
+  }
+
+  .switch-button {
+    width: 34px;
+    height: 34px;
+    position: fixed;
+    // right: 5px;
+    // bottom: 300px;
+    z-index: 1000;
+    background-repeat: no-repeat;
+    background-size: 100% 100%;
+    pointer-events: auto;
+    transition: right 1s;
+  }
+  .icon-goto {
+    --image-monitor-goto: url('/@/assets/images/company/monitor-goto.png');
+    background-image: var(--image-monitor-goto);
+  }
+
+  .divider-line {
+    border-bottom: 1px solid white;
+  }
+</style>
+<style>
+  /* .balancePress .zxm-modal-confirm-title {
+    font-size: 20px;
+  } */
+  .balancePress .zxm-modal-confirm-content {
+    font-size: 22px;
+  }
+</style>

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

@@ -1063,6 +1063,8 @@
           ? 'mainLjWindRect'
           : selectData['modalTyoe'] === 'lijing_3'
           ? 'mainWindRect3'
+          : selectData['modalTyoe'] === 'lijing_1'
+          ? 'mainLjDtWindRect'
           : 'mainWindRect';
 
       frontMonitorIsShow.value = false;

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

@@ -5,6 +5,7 @@ import mainWindRect from './mainWind.threejs';
 import mainXjWindRect from './mainWind.xj.threejs';
 import mainLjWindRect from './mainWind.lj.threejs';
 import mainWindLj3 from './mainWind.li3.threejs';
+import mainWindLjDt from './mainWind.lidt.threejs';
 import useEvent from '../../../../utils/threejs/useEvent';
 import { getDictItemsByCode } from '/@/utils/dict';
 
@@ -20,6 +21,7 @@ let model: UseThree | undefined, //
   mainXjWindObj: mainXjWindRect | undefined,
   mainLjWindObj: mainLjWindRect | undefined,
   mainLj3WindObj: mainWindLj3 | undefined,
+  mainFanLjDtObj: mainWindLjDt | undefined,
   modalType = 'mainWindRect',
   explosionVentClose = -1,
   explosionVentOpen = -1;
@@ -78,6 +80,8 @@ const mouseEvent = (event) => {
         mainXjWindObj?.mousedownModel.call(mainXjWindObj, intersects);
       } else if (modalType === 'mainWindRect3' && mainLj3WindObj) {
         mainLj3WindObj?.mousedownModel.call(mainLj3WindObj, intersects);
+      } else if (modalType === 'mainLjDtWindRect' && mainFanLjDtObj) {
+        mainFanLjDtObj?.mousedownModel.call(mainFanLjDtObj, intersects);
       }
     });
   }
@@ -104,6 +108,8 @@ export const addText = () => {
     return mainLjWindObj.addCssText.call(mainLjWindObj);
   } else if (modalType === 'mainWindRect3' && mainLj3WindObj) {
     return mainLj3WindObj.addCssText.call(mainLj3WindObj);
+  } else if (modalType === 'mainLjDtWindRect' && mainFanLjDtObj) {
+    return mainFanLjDtObj.addCssText.call(mainFanLjDtObj);
   }
 };
 
@@ -140,6 +146,8 @@ export const play = (controlType, deviceType, frequencyVal?, state?, smokeDirect
     return mainLjWindObj.playSmoke.call(mainLjWindObj, controlType, deviceType, frequencyVal, state, smokeDirection);
   } else if (modalType === 'mainWindRect3' && mainLj3WindObj) {
     return mainLj3WindObj.playSmoke.call(mainLj3WindObj, controlType, deviceType, frequencyVal, state, smokeDirection);
+  } else if (modalType === 'mainLjDtWindRect' && mainFanLjDtObj) {
+    return mainFanLjDtObj.playSmoke.call(mainFanLjDtObj, controlType, deviceType, frequencyVal, state, smokeDirection);
   }
 };
 
@@ -155,6 +163,8 @@ export const playAnimate1 = async (selectData, duration?) => {
     mainObj = mainLjWindObj;
   } else if (modalType === 'mainWindRect3') {
     mainObj = mainLj3WindObj;
+  } else if (modalType === 'mainLjDtWindRect') {
+    mainObj = mainFanLjDtObj;
   }
   if (selectData && mainObj) {
     if (selectData.Fan1WindowOpen !== undefined) {
@@ -237,7 +247,7 @@ export const playAnimate = async (selectData, duration?) => {
   // if (Number(selectData.Fan2FreqHz) < 0) selectData.Fan2FreqHz = Math.abs(Number(selectData.Fan2FreqHz));
   if (!mainWindObj) return;
 
-  let mainObj: mainWindRect | mainXjWindRect | mainWindLj3 | undefined;
+  let mainObj: mainWindRect | mainXjWindRect | mainWindLj3 | mainWindLjDt | undefined;
 
   if (modalType === 'mainWindRect') {
     mainObj = mainWindObj;
@@ -247,6 +257,8 @@ export const playAnimate = async (selectData, duration?) => {
     mainObj = mainLjWindObj;
   } else if (modalType === 'mainWindRect3') {
     mainObj = mainLj3WindObj;
+  } else if (modalType === 'mainLjDtWindRect') {
+    mainObj = mainFanLjDtObj;
   }
   if (selectData && mainObj) {
     if (selectData['Fan1FreqHz'] == undefined || selectData['Fan1FreqHz'] == null || selectData['Fan1FreqHz'] == '') selectData['Fan1FreqHz'] = 50;
@@ -331,6 +343,8 @@ export const playAnimate = async (selectData, duration?) => {
         // 主风机停止
         mainObj.closeDevice('back');
       }
+    } else if (modalType === 'mainLjDtWindRect') {
+      (mainObj as mainWindLjDt).playSmoke(selectData.Fan1StartStatus == 1, selectData.Fan2FreqForwardRun == 1, selectData.Fan2FreqReverseRun == 1);
     } else {
       mainObj.resetSmokeParam('front', selectData.Fan2FreqHz, duration);
       mainObj.resetSmokeParam('back', selectData.Fan1FreqHz, duration);
@@ -456,6 +470,7 @@ export const setModelType = (type) => {
     mainWindObj?.stopSmoke();
     mainXjWindObj?.stopSmoke();
     mainLj3WindObj?.stopSmoke();
+    mainFanLjDtObj?.stopSmoke();
     mainLjWindObj?.stopSmoke();
     if (group) model?.scene?.remove(group);
     if (modalType === 'mainWindRect' && mainWindObj && mainWindObj.group) {
@@ -529,6 +544,23 @@ export const setModelType = (type) => {
         );
         if (group) model?.scene?.add(group);
       }, 300);
+    } else if (modalType === 'mainLjDtWindRect' && mainFanLjDtObj && mainFanLjDtObj.group) {
+      (<UseThree>model).startAnimation = mainFanLjDtObj.render.bind(mainFanLjDtObj);
+      group = mainFanLjDtObj.group;
+      setTimeout(async () => {
+        resolve(null);
+        const position = new THREE.Vector3(2.815, -7.014, -5.985);
+        const oldCameraPosition = { x: -332.39, y: 283.47, z: 438.61 };
+        await animateCamera(
+          oldCameraPosition,
+          { x: -3.41, y: -29.01, z: 8.84 },
+          { x: 5.128, y: 72.363, z: 93.655 },
+          { x: position.x, y: position.y, z: position.z },
+          model,
+          0.8
+        );
+        if (group) model?.scene?.add(group);
+      }, 300);
     }
   });
 };
@@ -576,6 +608,11 @@ export const mountedThree = (playerVal1) => {
               mainLj3WindObj = new mainWindLj3(model, playerVal1);
               await mainLj3WindObj.mountedThree();
               break;
+            case 'lijing_1':
+              modalType = 'mainLjDtWindRect';
+              mainFanLjDtObj = new mainWindLjDt(model);
+              await mainFanLjDtObj.mountedThree();
+              break;
           }
         }
       } else {
@@ -609,6 +646,12 @@ export const mountedThree = (playerVal1) => {
         if (mainLj3WindObj.airJin2) mainLj3WindObj.airJin2.visible = false;
         if (mainLj3WindObj.airChu1) mainLj3WindObj.airChu1.visible = false;
       }
+      if (mainFanLjDtObj) {
+        // if (mainFanLjDtObj.airChu2) mainFanLjDtObj.airChu2.visible = false;
+        // if (mainFanLjDtObj.airJin1) mainFanLjDtObj.airJin1.visible = false;
+        // if (mainFanLjDtObj.airJin2) mainFanLjDtObj.airJin2.visible = false;
+        // if (mainFanLjDtObj.airChu1) mainFanLjDtObj.airChu1.visible = false;
+      }
     });
     startAnimation();
   });

+ 199 - 0
src/views/vent/monitorManager/mainFanMonitor/mainWind.lidt.threejs.ts

@@ -0,0 +1,199 @@
+import * as THREE from 'three';
+import ArrowFlow from '/@/views/vent/comment/threejs/ArrowFlow';
+import Smoke from '/@/views/vent/comment/threejs/Smoke';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class mainWindLjDt {
+  model;
+  modelName = 'main';
+  group: THREE.Group | null = null; // 主通风机场景
+
+  /** 进气箭头,这里指风机吸入气体 */
+  airIn: ArrowFlow | null = null;
+  /** 出气箭头,这里指风机排出气体 */
+  airOut: ArrowFlow | null = null;
+  /** 烟雾粒子,配合风机吸入气体时使用 */
+  smokeIn: Smoke | null = null;
+  /** 烟雾粒子,配合风机排出气体时使用 */
+  smokeOut: Smoke | null = null;
+
+  constructor(model) {
+    this.model = model;
+  }
+  // 添加 cssObject
+  addCssText() {
+    if (!this.group) return;
+  }
+
+  clearCssText() {}
+
+  /* 更新动画 */
+  render() {
+    if (!this.model) return;
+  }
+
+  /* 点击风窗,风窗全屏 */
+  mousedownModel() {}
+
+  mouseUpModel() {}
+
+  /**
+   * 播放气流动画
+   * @param FanStart // 风机启动
+   * @param FanForward // 风机正转排风
+   * @param FanReverse // 风机反转吸风
+   */
+  async playSmoke(FanStart, FanForward, FanReverse) {
+    if (!this.model) return;
+
+    if (!FanStart) {
+      // 风机停机
+      this.stopSmoke();
+    } else if (FanForward && !FanReverse) {
+      // 确认风机正转
+      this.airOut?.showElement();
+      if (!this.smokeOut?.frameId) {
+        // 如果没在播放再call这个方法
+        this.smokeOut?.startSmoke();
+      }
+    } else if (FanReverse && !FanForward) {
+      // 确认风机反转
+      this.airIn?.showElement();
+      if (!this.smokeIn?.frameId) {
+        // 如果没在播放再call这个方法
+        this.smokeIn?.startSmoke();
+      }
+    } else {
+      // 默认风机正转
+      this.airOut?.showElement();
+      if (!this.smokeOut?.frameId) {
+        // 如果没在播放再call这个方法
+        this.smokeOut?.startSmoke();
+      }
+    }
+  }
+  stopSmoke() {
+    this.airIn?.hideElement();
+    this.airOut?.hideElement();
+
+    this.smokeIn?.stopSmoke();
+    this.smokeOut?.stopSmoke();
+  }
+
+  /* 初始化 进气出气箭头、烟雾元素  */
+  initAnimationElements() {
+    const arrows = [
+      {
+        texturePath: '/model/img/greenArrow.png',
+        id: 'airIn',
+        offsetY: 0,
+        repeatX: 5,
+        rotation: Math.PI,
+        points: [new THREE.Vector3(21.07, 10.441, -5.816), new THREE.Vector3(8.693, 10.441, -5.816)],
+      },
+      {
+        texturePath: '/model/img/greenArrow.png',
+        id: 'airOut',
+        offsetY: 0,
+        repeatX: 5,
+        rotation: 0,
+        points: [new THREE.Vector3(8.693, 10.441, -5.816), new THREE.Vector3(21.07, 10.441, -5.816)],
+      },
+    ];
+
+    arrows.forEach(({ points, id, texturePath, repeatX, rotation }) => {
+      // 初始化箭头,偏移设置为0.25可以让贴图在管道上方
+      const arrow = new ArrowFlow(texturePath as any, {
+        repeatX,
+        repeatY: 1,
+        rotation,
+      });
+      // 这里开启动画后隐藏元素可以让后续动画控制仅调用 show/hideElement 即可
+      arrow.startAnimation();
+      arrow.hideElement();
+      const width = Math.abs(points[1].x - points[0].x);
+
+      // 添加几何,几何为一个二维简单几何
+      const geometry = new THREE.PlaneGeometry(width, 2);
+      const mesh = new THREE.Mesh(geometry, arrow);
+      mesh.position.set(8.693 + width / 2, 10.441, -5.816);
+      this[id] = arrow;
+      this.group?.add(mesh);
+    });
+
+    this.smokeOut = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.4, 1.8, 100);
+    this.smokeOut.setPath([
+      // {
+      //   path0: new THREE.Vector3(26.956, 7.138, -5.816),
+      //   path1: new THREE.Vector3(26.956, 17.016, -5.816),
+      //   isSpread: false,
+      //   spreadDirection: 0,
+      // },
+      {
+        path0: new THREE.Vector3(26.956, 10.016, -5.816),
+        path1: new THREE.Vector3(26.956, 26.913, -5.816),
+        isSpread: true,
+        spreadDirection: 1, // 1是由小变大(出),-1是由大变小(进)
+      },
+    ]);
+    this.smokeIn = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.4, 1.8, 100);
+    this.smokeIn.setPath([
+      // {
+      //   path0: new THREE.Vector3(26.956, 7.138, -5.816),
+      //   path1: new THREE.Vector3(26.956, 17.016, -5.816),
+      //   isSpread: false,
+      //   spreadDirection: 0,
+      // },
+      {
+        path0: new THREE.Vector3(26.956, 26.913, -5.816),
+        path1: new THREE.Vector3(26.956, 10.016, -5.816),
+        isSpread: true,
+        spreadDirection: -1, // 1是由小变大(出),-1是由大变小(进)
+      },
+    ]);
+
+    this.smokeIn?.setPoints().then(() => {
+      this.group?.add(this.smokeIn?.points);
+    });
+    this.smokeOut?.setPoints().then(() => {
+      this.group?.add(this.smokeOut?.points);
+    });
+  }
+
+  mountedThree() {
+    return new Promise(async (resolve) => {
+      this.model.setGLTFModel(['mainFanLjDt'], this.group).then(async (gltf) => {
+        this.group = gltf[0];
+
+        this.group?.position.set(4, 20.6, 22);
+        this.group?.scale.set(1.2, 1.2, 1.2);
+        await this.initAnimationElements();
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.model = undefined;
+    this.group = null;
+  }
+
+  resetSmokeParam() {}
+
+  openDevice() {}
+
+  closeDevice() {}
+
+  lookMotor() {}
+
+  openOrCloseValve() {}
+
+  startGearAnimation() {}
+
+  setSmokeDirection() {}
+}
+
+export default mainWindLjDt;