Prechádzať zdrojové kódy

[Feat 0000]上湾煤矿风门反馈推力曲线模块

bobo04052021@163.com 2 dní pred
rodič
commit
b40f16468b
23 zmenil súbory, kde vykonal 4862 pridanie a 2699 odobranie
  1. BIN
      src/assets/images/vent/lr-tab-bg.png
  2. 41 0
      src/views/vent/deviceManager/comment/warningTabel/warning.data.ts
  3. 361 357
      src/views/vent/home/colliery/components/wind-line.vue
  4. 20 11
      src/views/vent/home/configurable/components/ModuleCommon.vue
  5. 46 45
      src/views/vent/home/configurable/components/ModuleOriginal.vue
  6. 10 8
      src/views/vent/home/configurable/components/original/moduleBottom.vue
  7. 10 8
      src/views/vent/home/configurable/components/original/moduleLeft.vue
  8. 100 0
      src/views/vent/home/configurable/components/original/moduleRight.vue
  9. 34 4
      src/views/vent/home/configurable/ventSDG.vue
  10. 2 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.api.ts
  11. 2 2
      src/views/vent/monitorManager/balancePressMonitor/balancePress.data.ts
  12. 210 155
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressHomeBD.vue
  13. 17 6
      src/views/vent/monitorManager/balancePressMonitor/hooks/useControl.ts
  14. 146 20
      src/views/vent/monitorManager/comment/GroupMonitorTable.vue
  15. 583 583
      src/views/vent/monitorManager/comment/HistoryTable.vue
  16. 593 0
      src/views/vent/monitorManager/comment/HistoryTableChart.vue
  17. 17 5
      src/views/vent/monitorManager/gateMonitor/gate.data.ts
  18. 776 737
      src/views/vent/monitorManager/gateMonitor/index.vue
  19. 85 81
      src/views/vent/monitorManager/mainFanMonitor/components/AnalysisTable.vue
  20. 768 576
      src/views/vent/monitorManager/mainFanMonitor/index.vue
  21. 2 2
      src/views/vent/monitorManager/mainFanMonitor/main.data.ts
  22. 252 99
      src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts
  23. 787 0
      src/views/vent/monitorManager/mainFanMonitor/mainWind.li3.threejs.ts

BIN
src/assets/images/vent/lr-tab-bg.png


+ 41 - 0
src/views/vent/deviceManager/comment/warningTabel/warning.data.ts

@@ -46,6 +46,33 @@ export const levelColumns: BasicColumn[] = [
     dataIndex: 'des',
     editComponent: 'Input',
   },
+  {
+    title: '是否语音播报',
+    width: 110,
+    editRow: true,
+    dataIndex: 'isVoice',
+    editComponent: 'Switch',
+    editValueMap: (value) => {
+      return value ? '是' : '否';
+    },
+  },
+  {
+    title: '是否持续语音播报',
+    width: 130,
+    editRow: true,
+    dataIndex: 'isCxVoice',
+    editComponent: 'Switch',
+    editValueMap: (value) => {
+      return value ? '是' : '否';
+    },
+  },
+  {
+    title: '持续播报频率(s)',
+    width: 120,
+    editRow: true,
+    dataIndex: 'voiceFre',
+    editComponent: 'InputNumber',
+  },
 ];
 
 export const warningColumns: BasicColumn[] = [
@@ -470,6 +497,20 @@ export const monitorWarningFormSchemas = (param) =>
       field: 'cxTime',
       component: 'InputNumber',
     },
+    {
+      label: '数据趋势',
+      field: 'dataTrend',
+      component: 'JDictSelectTag',
+      componentProps: {
+        dictCode: 'dataTrend',
+        placeholder: '请选择数据趋势',
+      },
+    },
+    {
+      label: '数据趋势持续时间(h)',
+      field: 'trendCxTime',
+      component: 'InputNumber',
+    },
   ];
 
 export const controlWarningFormSchemas: FormSchema[] = [

+ 361 - 357
src/views/vent/home/colliery/components/wind-line.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="windLine">
-    <div class="title-top">关键通风路线智能管控</div>
+    <div class="title-top" @click="getDetail">关键通风路线智能管控</div>
     <div class="toggle-search">
       <i class="icon-search">
         <SvgIcon class="icon" size="14" name="toggle" />
@@ -45,418 +45,422 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, reactive, onMounted, nextTick, defineProps, watch } from 'vue';
-import { SvgIcon } from '/@/components/Icon';
-import * as echarts from 'echarts';
-import { formatNum } from '/@/utils/ventutil';
-
-const emit = defineEmits(['goDetail']);
-
-let props = defineProps({
-  lineList: Array,
-});
-
-//获取dom节点
-let line = ref<any>();
-let lineData = reactive<any[]>([]);
-let searchValue = ref('');
-const lineTypeList = reactive<any[]>([]);
-
-let echartData = reactive<any[]>([
-  { name: '进风区', value: 0 },
-  { name: '用风区', value: 0 },
-  { name: '回风区', value: 0 },
-]);
-let xData = reactive<any[]>([]);
-let yData = reactive<any[]>([]);
-let percentE = ref<any>(0);
-let percentF = ref<any>(0);
-let percentT = ref<any>(0);
-
-let tabList = reactive<any[]>([
-  { name: '总风量(m³/min)', val: 0 },
-  { name: '总阻力(Pa)', val: 0 },
-  { name: '等积孔(m²)', val: 0 },
-]);
-//跳转详情
-function getDetail() {
-  emit('goDetail', { deviceType: 'majorpath', id: searchValue.value });
-}
-//选项切换
-function changeSelect(val) {
-  searchValue.value = val;
-  const selectData = lineData.find((item) => item['deviceID'] == val);
-  if (selectData) {
-    echartData[0].value = (selectData.majorpath['drag_1'] || Math.floor(Math.random() * (629 - 620 + 1)) + 620).toFixed(2);
-    echartData[1].value = (selectData.majorpath['drag_2'] || Math.floor(Math.random() * (949 - 940 + 1)) + 940).toFixed(2);
-    echartData[2].value = (selectData.majorpath['drag_3'] || Math.floor(Math.random() * (855 - 850 + 1)) + 850).toFixed(2);
-    tabList[0].val = (selectData.majorpath['m3_total'] || Math.floor(Math.random() * (10700 - 10600 + 1)) + 10600).toFixed(2);
-    tabList[1].val = (selectData.majorpath['drag_total'] || Math.floor(Math.random() * (2433 - 2423 + 1)) + 2423).toFixed(2);
-    tabList[2].val = formatNum((1.19 * Number(tabList[0].val)) / 60 / Math.sqrt(Number(tabList[1].val)));
-    percentF.value = formatNum(
-      (Number(echartData[0].value) / (Number(echartData[0].value) + Number(echartData[1].value) + Number(echartData[2].value))) * 100
-    );
-    percentT.value = formatNum(
-      (Number(echartData[1].value) / (Number(echartData[0].value) + Number(echartData[1].value) + Number(echartData[2].value))) * 100
-    );
-    percentE.value = formatNum(
-      (echartData[2].value / (Number(echartData[0].value) + Number(echartData[1].value) + Number(echartData[2].value))) * 100
-    );
+  import { ref, reactive, onMounted, nextTick, defineProps, watch } from 'vue';
+  import { SvgIcon } from '/@/components/Icon';
+  import * as echarts from 'echarts';
+  import { formatNum } from '/@/utils/ventutil';
+  import { useGlobSetting } from '/@/hooks/setting';
+
+  const emit = defineEmits(['goDetail']);
+
+  let props = defineProps({
+    lineList: Array,
+  });
+
+  const { sysOrgCode } = useGlobSetting();
+
+  //获取dom节点
+  let line = ref<any>();
+  let lineData = reactive<any[]>([]);
+  let searchValue = ref('');
+  const lineTypeList = reactive<any[]>([]);
+
+  let echartData = reactive<any[]>([
+    { name: '进风区', value: 0 },
+    { name: '用风区', value: 0 },
+    { name: '回风区', value: 0 },
+  ]);
+  let xData = reactive<any[]>([]);
+  let yData = reactive<any[]>([]);
+  let percentE = ref<any>(0);
+  let percentF = ref<any>(0);
+  let percentT = ref<any>(0);
+
+  let tabList = reactive<any[]>([
+    { name: '总风量(m³/min)', val: 0 },
+    { name: '总阻力(Pa)', val: 0 },
+    { name: '等积孔(m²)', val: 0 },
+  ]);
+  //跳转详情
+  function getDetail() {
+    if (sysOrgCode === 'hnjtymhmk') return; //羊马河暂时屏蔽跳转
+    emit('goDetail', { deviceType: 'majorpath', id: searchValue.value });
   }
-  getOption();
-}
-
-function getOption() {
-  nextTick(() => {
-    function deepCopy(obj) {
-      if (typeof obj !== 'object') {
-        return obj;
-      }
-      var newobj = {};
-      for (var attr in obj) {
-        newobj[attr] = obj[attr];
-      }
-      return newobj;
+  //选项切换
+  function changeSelect(val) {
+    searchValue.value = val;
+    const selectData = lineData.find((item) => item['deviceID'] == val);
+    if (selectData) {
+      echartData[0].value = (selectData.majorpath['drag_1'] || Math.floor(Math.random() * (629 - 620 + 1)) + 620).toFixed(2);
+      echartData[1].value = (selectData.majorpath['drag_2'] || Math.floor(Math.random() * (949 - 940 + 1)) + 940).toFixed(2);
+      echartData[2].value = (selectData.majorpath['drag_3'] || Math.floor(Math.random() * (855 - 850 + 1)) + 850).toFixed(2);
+      tabList[0].val = (selectData.majorpath['m3_total'] || Math.floor(Math.random() * (10700 - 10600 + 1)) + 10600).toFixed(2);
+      tabList[1].val = (selectData.majorpath['drag_total'] || Math.floor(Math.random() * (2433 - 2423 + 1)) + 2423).toFixed(2);
+      tabList[2].val = formatNum((1.19 * Number(tabList[0].val)) / 60 / Math.sqrt(Number(tabList[1].val)));
+      percentF.value = formatNum(
+        (Number(echartData[0].value) / (Number(echartData[0].value) + Number(echartData[1].value) + Number(echartData[2].value))) * 100
+      );
+      percentT.value = formatNum(
+        (Number(echartData[1].value) / (Number(echartData[0].value) + Number(echartData[1].value) + Number(echartData[2].value))) * 100
+      );
+      percentE.value = formatNum(
+        (echartData[2].value / (Number(echartData[0].value) + Number(echartData[1].value) + Number(echartData[2].value))) * 100
+      );
     }
+    getOption();
+  }
 
-    echartData.map((a, b) => {
-      xData.push(a.name);
-      yData.push(a.value);
-    });
-    var startColor = ['rgba(255, 224, 28,.6)', 'rgba(31, 248, 251,.6)', 'rgba(154, 255, 168,.6)'];
-    var borderStartColor = ['#ffe01c', '#1ff8fb', '#9affa8'];
-    var RealData = [];
-    var borderData = [];
-    echartData.map((item, index) => {
-      var newobj = deepCopy(item);
-      var newobj1 = deepCopy(item);
-      RealData.push(newobj);
-      borderData.push(newobj1);
-    });
-    RealData.map((item, index) => {
-      item.itemStyle = {
-        normal: {
-          color: startColor[index],
-        },
-      };
-    });
-    borderData.map((item, index) => {
-      item.itemStyle = {
-        normal: {
-          color: borderStartColor[index],
-        },
-      };
-    });
-    const myChart = echarts.init(line.value);
-
-    let option = {
-      legend: [
-        {
-          // orient: 'vertical',
-          x: '50%',
-          y: '12%',
-          itemWidth: 10,
-          itemHeight: 10,
-          align: 'left',
-          textStyle: {
-            fontSize: 14,
-            color: '#b3b8cc',
-          },
-          data: ['进风区'],
-        },
-        {
-          // orient: 'vertical',
-          x: '50%',
-          y: '42%',
-          itemWidth: 10,
-          itemHeight: 10,
-          align: 'left',
-          textStyle: {
-            fontSize: 14,
-            color: '#b3b8cc',
+  function getOption() {
+    nextTick(() => {
+      function deepCopy(obj) {
+        if (typeof obj !== 'object') {
+          return obj;
+        }
+        var newobj = {};
+        for (var attr in obj) {
+          newobj[attr] = obj[attr];
+        }
+        return newobj;
+      }
+
+      echartData.map((a, b) => {
+        xData.push(a.name);
+        yData.push(a.value);
+      });
+      var startColor = ['rgba(255, 224, 28,.6)', 'rgba(31, 248, 251,.6)', 'rgba(154, 255, 168,.6)'];
+      var borderStartColor = ['#ffe01c', '#1ff8fb', '#9affa8'];
+      var RealData = [];
+      var borderData = [];
+      echartData.map((item, index) => {
+        var newobj = deepCopy(item);
+        var newobj1 = deepCopy(item);
+        RealData.push(newobj);
+        borderData.push(newobj1);
+      });
+      RealData.map((item, index) => {
+        item.itemStyle = {
+          normal: {
+            color: startColor[index],
           },
-          data: ['用风区'],
-        },
-        {
-          // orient: 'vertical',
-          x: '50%',
-          y: '70%',
-          itemWidth: 10,
-          itemHeight: 10,
-          align: 'left',
-          textStyle: {
-            fontSize: 14,
-            color: '#b3b8cc',
+        };
+      });
+      borderData.map((item, index) => {
+        item.itemStyle = {
+          normal: {
+            color: borderStartColor[index],
           },
-          data: ['回风区'],
-        },
-      ],
-      tooltip: {
-        formatter: '{b}:{c}',
-      },
-      series: [
-        // 主要展示层的
-        {
-          radius: ['40%', '80%'],
-          center: ['25%', '50%'],
-          type: 'pie',
-          z: 10,
-          label: {
-            normal: {
-              show: false,
-            },
-            emphasis: {
-              show: false,
+        };
+      });
+      const myChart = echarts.init(line.value);
+
+      let option = {
+        legend: [
+          {
+            // orient: 'vertical',
+            x: '50%',
+            y: '12%',
+            itemWidth: 10,
+            itemHeight: 10,
+            align: 'left',
+            textStyle: {
+              fontSize: 14,
+              color: '#b3b8cc',
             },
+            data: ['进风区'],
           },
-          labelLine: {
-            normal: {
-              show: false,
-            },
-            emphasis: {
-              show: false,
+          {
+            // orient: 'vertical',
+            x: '50%',
+            y: '42%',
+            itemWidth: 10,
+            itemHeight: 10,
+            align: 'left',
+            textStyle: {
+              fontSize: 14,
+              color: '#b3b8cc',
             },
+            data: ['用风区'],
           },
-          itemStyle: {
-            normal: {
-              borderWidth: 5,
-              borderColor: 'rgba(1, 57, 134,1)',
+          {
+            // orient: 'vertical',
+            x: '50%',
+            y: '70%',
+            itemWidth: 10,
+            itemHeight: 10,
+            align: 'left',
+            textStyle: {
+              fontSize: 14,
+              color: '#b3b8cc',
             },
+            data: ['回风区'],
           },
-          data: RealData,
+        ],
+        tooltip: {
+          formatter: '{b}:{c}',
         },
-        // 边框的设置
-        {
-          radius: ['45%', '52%'],
-          center: ['25%', '50%'],
-          type: 'pie',
-          z: 5,
-          label: {
-            normal: {
-              show: false,
+        series: [
+          // 主要展示层的
+          {
+            radius: ['40%', '80%'],
+            center: ['25%', '50%'],
+            type: 'pie',
+            z: 10,
+            label: {
+              normal: {
+                show: false,
+              },
+              emphasis: {
+                show: false,
+              },
             },
-            emphasis: {
-              show: false,
+            labelLine: {
+              normal: {
+                show: false,
+              },
+              emphasis: {
+                show: false,
+              },
+            },
+            itemStyle: {
+              normal: {
+                borderWidth: 5,
+                borderColor: 'rgba(1, 57, 134,1)',
+              },
             },
+            data: RealData,
           },
-          labelLine: {
-            normal: {
-              show: false,
+          // 边框的设置
+          {
+            radius: ['45%', '52%'],
+            center: ['25%', '50%'],
+            type: 'pie',
+            z: 5,
+            label: {
+              normal: {
+                show: false,
+              },
+              emphasis: {
+                show: false,
+              },
+            },
+            labelLine: {
+              normal: {
+                show: false,
+              },
+              emphasis: {
+                show: false,
+              },
             },
-            emphasis: {
+
+            animation: false,
+            tooltip: {
               show: false,
             },
+            data: borderData,
           },
+        ],
+      };
+      myChart.setOption(option);
+      window.onresize = function () {
+        myChart.resize();
+      };
+    });
+  }
 
-          animation: false,
-          tooltip: {
-            show: false,
-          },
-          data: borderData,
-        },
-      ],
-    };
-    myChart.setOption(option);
-    window.onresize = function () {
-      myChart.resize();
-    };
-  });
-}
-
-watch(
-  () => props.lineList,
-  (val) => {
-    lineData = val;
-    lineTypeList.length = 0;
-    lineData.forEach((el) => {
-      lineTypeList.push({
-        label: el.deviceName,
-        value: el.deviceID,
+  watch(
+    () => props.lineList,
+    (val) => {
+      lineData = val;
+      lineTypeList.length = 0;
+      lineData.forEach((el) => {
+        lineTypeList.push({
+          label: el.deviceName,
+          value: el.deviceID,
+        });
       });
-    });
 
-    if (searchValue.value) {
-      changeSelect(searchValue.value);
-    } else {
-      searchValue.value = lineTypeList[0].value;
-      changeSelect(searchValue.value);
+      if (searchValue.value) {
+        changeSelect(searchValue.value);
+      } else {
+        searchValue.value = lineTypeList[0].value;
+        changeSelect(searchValue.value);
+      }
+    },
+    {
+      deep: true,
     }
-  },
-  {
-    deep: true,
-  }
-);
+  );
 
-onMounted(() => {});
+  onMounted(() => {});
 </script>
 
 <style lang="less" scoped>
-@font-face {
-  font-family: 'douyuFont';
-  src: url('../../../../../assets/font/douyuFont.otf');
-}
-
-.windLine {
-  width: 100%;
-  height: 100%;
-  position: relative;
-
-  .title-top {
-    position: absolute;
-    top: 9px;
-    left: 46px;
-    color: #fff;
-    font-size: 16px;
+  @font-face {
     font-family: 'douyuFont';
-    cursor: pointer;
-
-    &:hover {
-      color: #66ffff;
-    }
+    src: url('../../../../../assets/font/douyuFont.otf');
   }
 
-  .toggle-search {
-    position: absolute;
-    left: 9px;
-    top: 37px;
-    display: flex;
-
-    .icon-search {
-      position: absolute;
-      top: 50%;
-      left: 5px;
-      transform: translate(0%, -50%);
-    }
-  }
-
-  .line-echart {
-    position: absolute;
-    top: 66px;
-    left: 0;
+  .windLine {
     width: 100%;
-    height: 120px;
+    height: 100%;
+    position: relative;
 
-    .line {
-      width: 100%;
-      height: 100%;
+    .title-top {
+      position: absolute;
+      top: 9px;
+      left: 46px;
+      color: #fff;
+      font-size: 16px;
+      font-family: 'douyuFont';
+      cursor: pointer;
+
+      &:hover {
+        color: #66ffff;
+      }
     }
 
-    .pic {
-      height: 100%;
+    .toggle-search {
       position: absolute;
-      left: 45%;
-      top: 0;
+      left: 9px;
+      top: 37px;
       display: flex;
-      align-items: center;
 
-      img {
-        height: 60%;
+      .icon-search {
+        position: absolute;
+        top: 50%;
+        left: 5px;
+        transform: translate(0%, -50%);
       }
     }
 
-    .percent {
+    .line-echart {
       position: absolute;
-      left: 75%;
-      top: 0;
-      width: 45px;
-      height: 100%;
-      display: flex;
-      flex-direction: column;
-      // justify-content: space-between;
-      align-items: center;
+      top: 66px;
+      left: 0;
+      width: 100%;
+      height: 120px;
 
-      .percent-box {
-        font-size: 14px;
+      .line {
+        width: 100%;
+        height: 100%;
+      }
 
-        // color: #b3b8cc;
-        &:nth-child(1) {
-          position: absolute;
-          top: 12%;
-          color: #ffe01c;
-        }
+      .pic {
+        height: 100%;
+        position: absolute;
+        left: 45%;
+        top: 0;
+        display: flex;
+        align-items: center;
 
-        &:nth-child(2) {
-          position: absolute;
-          top: 42%;
-          color: #1ff8fb;
+        img {
+          height: 60%;
         }
+      }
 
-        &:nth-child(3) {
-          position: absolute;
-          top: 70%;
-          color: #9affa8;
-        }
+      .percent {
+        position: absolute;
+        left: 75%;
+        top: 0;
+        width: 45px;
+        height: 100%;
+        display: flex;
+        flex-direction: column;
+        // justify-content: space-between;
+        align-items: center;
+
+        .percent-box {
+          font-size: 14px;
 
-        .dw {
-          color: #b3b8cc;
-          margin-left: 5px;
+          // color: #b3b8cc;
+          &:nth-child(1) {
+            position: absolute;
+            top: 12%;
+            color: #ffe01c;
+          }
+
+          &:nth-child(2) {
+            position: absolute;
+            top: 42%;
+            color: #1ff8fb;
+          }
+
+          &:nth-child(3) {
+            position: absolute;
+            top: 70%;
+            color: #9affa8;
+          }
+
+          .dw {
+            color: #b3b8cc;
+            margin-left: 5px;
+          }
         }
       }
     }
-  }
 
-  .line-card {
-    position: absolute;
-    top: 186px;
-    left: 0;
-    width: 100%;
-    height: calc(100% - 186px);
-    padding: 0px 15px 15px 15px;
-    box-sizing: border-box;
-    display: flex;
-    justify-content: space-around;
-    align-items: center;
-
-    .card-item {
+    .line-card {
+      position: absolute;
+      top: 186px;
+      left: 0;
+      width: 100%;
+      height: calc(100% - 186px);
+      padding: 0px 15px 15px 15px;
+      box-sizing: border-box;
       display: flex;
-      flex: 1;
-      justify-content: center;
+      justify-content: space-around;
       align-items: center;
-      height: 100%;
-
-      .item-s {
-        position: relative;
-        width: 105px;
-        height: 58px;
-        margin-top: 20px;
-        background: url('../../../../../assets/images/home-container/line-val.png') no-repeat;
-        background-size: 100% 90%;
-
-        .item-label {
-          width: 100%;
-          text-align: center;
-          color: #b3b8cc;
-          font-size: 12px;
-        }
 
-        .item-val {
-          position: absolute;
-          left: 50%;
-          top: 26px;
-          font-size: 14px;
-          font-family: 'douyuFont';
-          color: #fff;
-          transform: translate(-50%, 0);
+      .card-item {
+        display: flex;
+        flex: 1;
+        justify-content: center;
+        align-items: center;
+        height: 100%;
+
+        .item-s {
+          position: relative;
+          width: 105px;
+          height: 58px;
+          margin-top: 20px;
+          background: url('../../../../../assets/images/home-container/line-val.png') no-repeat;
+          background-size: 100% 90%;
+
+          .item-label {
+            width: 100%;
+            text-align: center;
+            color: #b3b8cc;
+            font-size: 12px;
+          }
+
+          .item-val {
+            position: absolute;
+            left: 50%;
+            top: 26px;
+            font-size: 14px;
+            font-family: 'douyuFont';
+            color: #fff;
+            transform: translate(-50%, 0);
+          }
         }
       }
     }
   }
-}
-
-:deep .zxm-select-selector {
-  width: 100%;
-  height: 30px !important;
-  padding: 0 11px 0px 25px !important;
-  background-color: rgba(8, 148, 255, 0.3) !important;
-  border: 1px solid #1d80da !important;
-}
-
-:deep .zxm-select-selection-item {
-  color: #fff !important;
-  line-height: 28px !important;
-}
-
-:deep .zxm-select-arrow {
-  color: #fff !important;
-}
+
+  :deep .zxm-select-selector {
+    width: 100%;
+    height: 30px !important;
+    padding: 0 11px 0px 25px !important;
+    background-color: rgba(8, 148, 255, 0.3) !important;
+    border: 1px solid #1d80da !important;
+  }
+
+  :deep .zxm-select-selection-item {
+    color: #fff !important;
+    line-height: 28px !important;
+  }
+
+  :deep .zxm-select-arrow {
+    color: #fff !important;
+  }
 </style>

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

@@ -1,16 +1,21 @@
 <template>
   <!-- 常用模块 -->
-  <ventBox1 :class="getModuleClass(showStyle)" :style="style">
-    <template v-if="moduleName" #title>
-      <div :class="{ 'cursor-pointer': !!moduleData.to }" @click="redirectTo">{{ moduleName }}</div>
-    </template>
-    <template #container>
-      <slot>
-        <Header :deviceType="deviceType" :moduleData="moduleData" :data="data" @select="selectedData = $event" />
-        <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />
-      </slot>
-    </template>
-  </ventBox1>
+  <Transition
+    :enter-active-class="`animate__animated  animate__fadeIn${capitalizedPosition}`"
+    :leave-active-class="`animate__animated  animate__fadeOut${capitalizedPosition}`"
+  >
+    <ventBox1 v-if="visible" :class="getModuleClass(showStyle)" :style="style">
+      <template v-if="moduleName" #title>
+        <div :class="{ 'cursor-pointer': !!moduleData.to }" @click="redirectTo">{{ moduleName }}</div>
+      </template>
+      <template #container>
+        <slot>
+          <Header :deviceType="deviceType" :moduleData="moduleData" :data="data" @select="selectedData = $event" />
+          <Content :style="{ height: header.show ? 'calc(100% - 30px)' : '100%' }" :moduleData="moduleData" :data="selectedData" />
+        </slot>
+      </template>
+    </ventBox1>
+  </Transition>
 </template>
 <script lang="ts" setup>
   import Header from './header.vue';
@@ -46,6 +51,10 @@
     return size + position + 'position: absolute; pointer-events: auto;';
   });
 
+  const capitalizedPosition = computed(() => {
+    return props.showStyle.position.includes('left') ? 'Left' : 'Right';
+  });
+
   // 根据配置里的定位判断应该使用哪个class
   function getModuleClass({ size, position }) {
     const [_, width] = size.match(/width:([0-9]+)px/) || [];

+ 46 - 45
src/views/vent/home/configurable/components/ModuleOriginal.vue

@@ -16,56 +16,57 @@
   </component>
 </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 { 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 ModuleRight from './original/moduleRight.vue';
+  import ModuleBottom from './original/moduleBottom.vue';
+  import { computed, ref } from '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;
-}>();
-defineEmits(['close', 'click']);
+  const props = defineProps<{
+    /** 配置的详细模块信息 */
+    moduleData: any;
+    /** 配置的详细样式信息 */
+    showStyle: any;
+    /** 该模块配置中的设备标识符 */
+    deviceType: string;
+    /** api返回的数据 */
+    data: any;
+    moduleName: string;
+    visible: boolean;
+  }>();
+  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;
-});
+  const style = computed(() => {
+    const size = props.showStyle.size;
+    const position = props.showStyle.position;
+    return size + position;
+  });
 
-// 根据配置里的定位判断应该使用哪个module组件
-function getModuleComponent({ size, position }) {
-  const [_, width] = size.match(/width:([0-9]+)px/) || [];
-  if (position.includes('bottom') || parseInt(width) > 800) {
+  // 根据配置里的定位判断应该使用哪个module组件
+  function getModuleComponent({ size, position }) {
+    const [_, width] = size.match(/width:([0-9]+)px/) || [];
+    if (position.includes('bottom') || parseInt(width) > 800) {
+      return ModuleBottom;
+    }
+    if (position.includes('left')) {
+      return ModuleLeft;
+    }
+    if (position.includes('right')) {
+      return ModuleRight;
+    }
     return ModuleBottom;
   }
-  if (position.includes('left')) {
-    return ModuleLeft;
-  }
-  if (position.includes('right')) {
-    return ModuleLeft;
-  }
-  return ModuleBottom;
-}
 
-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>

+ 10 - 8
src/views/vent/home/configurable/components/original/moduleBottom.vue

@@ -1,13 +1,15 @@
 <template>
-  <div v-if="visible" class="module-content">
-    <div v-if="title" class="module-content__title__expand">
-      <span class="action-btn close-btn" @click="closeModel"></span>
-      <span @click="clickHandler">{{ title }}</span>
+  <Transition>
+    <div v-if="visible" class="module-content">
+      <div v-if="title" class="module-content__title__expand">
+        <span class="action-btn close-btn" @click="closeModel"></span>
+        <span @click="clickHandler">{{ title }}</span>
+      </div>
+      <div class="module-slot">
+        <slot></slot>
+      </div>
     </div>
-    <div class="module-slot">
-      <slot></slot>
-    </div>
-  </div>
+  </Transition>
 </template>
 <script lang="ts" setup>
   defineProps<{ title: string; visible: boolean }>();

+ 10 - 8
src/views/vent/home/configurable/components/original/moduleLeft.vue

@@ -1,13 +1,15 @@
 <template>
-  <div v-if="visible" class="module-content">
-    <div v-if="title" class="module-content__title__expand">
-      <span class="action-btn close-btn" @click="closeModel"></span>
-      <span @click="clickHandler">{{ title }}</span>
+  <Transition>
+    <div v-if="visible" class="module-content">
+      <div v-if="title" class="module-content__title__expand">
+        <span class="action-btn close-btn" @click="closeModel"></span>
+        <span @click="clickHandler">{{ title }}</span>
+      </div>
+      <div class="module-slot">
+        <slot></slot>
+      </div>
     </div>
-    <div class="module-slot">
-      <slot></slot>
-    </div>
-  </div>
+  </Transition>
 </template>
 <script lang="ts" setup>
   defineProps<{ title: string; visible: boolean }>();

+ 100 - 0
src/views/vent/home/configurable/components/original/moduleRight.vue

@@ -0,0 +1,100 @@
+<template>
+  <Transition>
+    <div v-if="visible" class="module-content">
+      <div v-if="title" class="module-content__title__expand">
+        <span class="action-btn close-btn" @click="closeModel"></span>
+        <span @click="clickHandler">{{ title }}</span>
+      </div>
+      <div class="module-slot">
+        <slot></slot>
+      </div>
+    </div>
+  </Transition>
+</template>
+<script lang="ts" setup>
+  // 和 ./moduleLeft 一样,针对动画做了一些修改
+  defineProps<{ title: string; visible: boolean }>();
+  const emit = defineEmits(['close', 'click']);
+
+  function closeModel() {
+    emit('close');
+  }
+  function clickHandler() {
+    emit('click');
+  }
+</script>
+<style lang="less" scoped>
+  @import '/@/design/theme.less';
+
+  @{theme-deepblue} {
+    .module-content {
+      --image-model_original_title_bg: url('@/assets/images/themify/deepblue/home-container/configurable/model_original_title_bg.png');
+    }
+  }
+
+  .module-content {
+    --image-model_original_title_bg: url('@/assets/images/home-container/configurable/model_original_title_bg.png');
+    --bg-height: 33px;
+    color: #fff;
+    box-sizing: border-box;
+    position: absolute;
+    width: 100%;
+    height: 100%;
+  }
+
+  .module-content__title__expand {
+    width: 100%;
+    height: var(--bg-height);
+    background: var(--image-model_original_title_bg) no-repeat;
+    background-size: 100% 100%;
+    position: relative;
+    text-align: center;
+    line-height: var(--bg-height);
+  }
+
+  // .module-content__title {
+  //   width: 50%;
+  //   height: var(--bg-height);
+  //   background: url('@/assets/images/home-container/configurable/model_left_title_bg.png') no-repeat;
+  //   background-size: 100% 100%;
+  //   position: relative;
+  //   text-align: right;
+  //   padding: 4px 10% 0 0;
+  // }
+
+  // 固定在父容器右上角的按钮图标
+  // .action-btn {
+  //   width: 18px;
+  //   height: 18px;
+  //   background: url('@/assets/images/home-container/configurable/expand.svg') no-repeat center;
+  //   position: absolute;
+  //   right: 0;
+  //   top: 0;
+  // }
+  // .close-btn {
+  //   transform: rotate(-90deg);
+  // }
+
+  .module-slot {
+    height: calc(100% - 33px);
+    width: calc(100% - 20px);
+    backdrop-filter: blur(5px);
+    // #182d47
+    background-color: var(--vent-configurable-original-module-bg);
+    margin-left: 10px;
+  }
+
+  // Transition动画相关
+  .v-enter-active,
+  .v-leave-active {
+    transition: all 0.3s ease;
+  }
+
+  .v-enter-from,
+  .v-leave-to {
+    // opacity: 1;
+    transform: translateX(100%);
+    // transform: scaleY(0);
+    // transform-origin: center top;
+  }
+</style>

+ 34 - 4
src/views/vent/home/configurable/ventSDG.vue

@@ -1,8 +1,25 @@
 <!-- eslint-disable vue/multi-word-component-names -->
 <template>
   <div class="company-home">
-    <div style="width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 0">
+    <CustomHeader> 三道沟煤矿均压综采面智能监测与动态调控 </CustomHeader>
+    <!-- <div style="width: 100%; height: 100%; position: absolute; left: 0; top: 0; z-index: 0">
       <VentModal />
+    </div> -->
+    <div class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden; z-index: 0">
+      <a-spin :spinning="loading" />
+      <div id="balancePress3D" v-show="!loading" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
+      <!-- <div id="damper3DCSS" v-show="!loading" style="width: 100%; height: 100%; top:0; left: 0; position: absolute; overflow: hidden;">
+      <div>
+        <div ref="elementContent" class="elementContent">
+          <p><span class="data-title">压力(Pa):</span>{{selectData.frontRearDP}}</p>
+          <p><span class="data-title">动力源压力(MPa):</span>{{selectData.sourcePressure}}</p>
+          <p><span class="data-title">故障诊断:</span>
+            <i
+              :class="{'state-icon': true, 'open': selectData.messageBoxStatus, 'close': !selectData.messageBoxStatus}"
+            ></i>{{selectData.fault}}</p>
+        </div>
+      </div>
+    </div> -->
     </div>
     <!-- 如果是有 deviceType、type 等 query,认为是详情页,不需要展示普通模块,只需要模型 -->
     <template v-if="!route.query.deviceType">
@@ -29,8 +46,11 @@
           :module-name="cfg.moduleName"
           :device-type="cfg.deviceType"
           :data="data"
-          :visible="true"
+          :visible="showModules"
         />
+
+        <div v-if="showModules" class="switch-button icon-goto right-475px bottom-300px" @click="showModules = false"></div>
+        <div v-else class="switch-button icon-goto right-20px bottom-20px" @click="showModules = true"></div>
       </template>
       <template v-else-if="isCommon">
         <ModuleCommon
@@ -71,11 +91,11 @@
         class="switch-button report-mode right-525px"
         @click="switchDataMode"
       ></div> -->
-      <div class="switch-button icon-goto right-475px" @click="goMicroApp()"></div>
     </template>
   </div>
 </template>
 <script lang="ts" setup>
+  import CustomHeader from '/@/components/vent/customHeader.vue';
   import { onMounted, onUnmounted, ref, watch } from 'vue';
   // import { CaretDownOutlined } from '@ant-design/icons-vue';
   // import MonitorBar from './components/MonitorBar.vue';
@@ -85,6 +105,7 @@
   import ModuleCommon from './components/ModuleCommon.vue';
   // import { useRoute } from 'vue-router';
   import VentModal from '/@/components/vent/micro/ventModal.vue';
+  import { mountedThree, destroy, setModelType, updateText, play } from '/@/views/vent/monitorManager/balancePressMonitor/balancePress.threejs';
   import { list } from './configurable.api';
   import { useRoute, useRouter } from 'vue-router';
   import { useGlobSetting } from '/@/hooks/setting';
@@ -97,6 +118,8 @@
   const router = useRouter();
   const isDataRealTime = ref(sysDataType === 'monitor');
   // const showBar = ref(true);
+  const loading = ref(false);
+  const showModules = ref(true);
   let interval: number | undefined;
 
   // function switchDataMode() {
@@ -184,9 +207,16 @@
   onMounted(() => {
     refresh();
     initInterval();
+
+    mountedThree().then(async () => {
+      await setModelType('balancePressTun'); //balancePressBase
+      loading.value = false;
+      play('startSmoke', 'top', 30, 'open', 0);
+    });
   });
 
   onUnmounted(() => {
+    destroy();
     clearInterval(interval);
   });
 </script>
@@ -280,7 +310,7 @@
       height: 34px;
       position: absolute;
       // right: 5px;
-      bottom: 300px;
+      // bottom: 300px;
       z-index: 5;
       background-repeat: no-repeat;
       background-size: 100% 100%;

+ 2 - 0
src/views/vent/monitorManager/balancePressMonitor/balancePress.api.ts

@@ -11,6 +11,7 @@ enum Api {
   updatePassword = '/monitor/demo/avePress/update/password',
   validPassword = '/monitor/demo/avePress/valid/password',
   controlWindow = '/monitor/demo/avePress/controlWindow',
+  cancelcontrolWindow = '/monitor/demo/avePress/cancel-controlWindow',
 }
 /**
  * 列表接口
@@ -50,6 +51,7 @@ export const subList2 = (params) => defHttp.get({ url: Api.subList2, params });
 export const submitEdit = (params) => defHttp.post({ url: Api.submitEdit, params });
 
 export const controlWindow = (params) => defHttp.get({ url: Api.controlWindow, params }, { joinParamsToUrl: true });
+export const cancelcontrolWindow = (params) => defHttp.get({ url: Api.cancelcontrolWindow, params }, { joinParamsToUrl: true });
 
 export const updatePassword = (params) =>
   defHttp.get({ url: Api.updatePassword, params }).then((e) => {

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

@@ -206,12 +206,12 @@ export const settingParam4 = [
     title: '氧气上限',
     code: 'o2MaxVal',
     value: '',
-    unit: 'm³/min',
+    unit: '%',
   },
   {
     title: '氧气下限',
     code: 'o2MinVal',
     value: '',
-    unit: 'm³/min',
+    unit: '%',
   },
 ];

+ 210 - 155
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHomeBD.vue

@@ -2,102 +2,96 @@
   <a-spin tip="Loading..." :spinning="loading">
     <div class="monitor-container">
       <div class="lr left-box">
-        <ventBox1>
-          <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.isAutoControl" name="radioGroup" @change="changeIsAutoControl">
-                <a-radio value="1">关闭</a-radio>
-                <a-radio value="2">开启</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="changeIsAutoControl">
-                <a-radio value="o2">氧气</a-radio>
-                <a-radio value="pressure">压差</a-radio>
-              </a-radio-group>
-            </div>
-            <div class="input-box">
-              <!-- <div class="divider-line">开始条件</div>
+        <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="o2">氧气</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 settingParam4" 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">{{ item.unit }}</div>
-              </div>
-              <!-- <div class="divider-line">结束时间</div>
+                <div class="divider-line"></div>
+                <div v-for="(item, index) in settingParam4" 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>
-      </div>
-      <div style="pointer-events: auto" class="flex mt-10px h-100% w-770px">
-        <ventBox1 class="mr-10px">
-          <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="gateLinkage.isAuto" name="radioGroup" @change="changeIsAuto($event, gateLinkage.id)">
-                <a-radio :value="false">关闭</a-radio>
-                <a-radio :value="true">开启</a-radio>
-              </a-radio-group>
-            </div>
-            <div class="btn-box" style="text-align: center">
-              <div class="btn btn1" @click="() => openModal(false, { id: gateLinkage.id })">控制密码修改</div>
-            </div>
-          </template>
-        </ventBox1>
-        <ventBox1>
-          <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="avePressLinkage.isAuto" name="radioGroup" @change="changeIsAuto($event, avePressLinkage.id)">
-                <a-radio :value="false">关闭</a-radio>
-                <a-radio :value="true">开启</a-radio>
-              </a-radio-group>
-            </div>
-            <div class="btn-box" style="text-align: center">
-              <div class="btn btn1" @click="() => openModal(false, { id: avePressLinkage.id })">控制密码修改</div>
-            </div>
-          </template>
-        </ventBox1>
+              </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>
+        <Transition enter-active-class="animate__animated  animate__fadeInLeft" leave-active-class="animate__animated  animate__fadeOutLeft">
+          <ventBox1 v-if="showModules" class="mt-10px">
+            <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="gateLinkage.isAuto" name="radioGroup" @change="changeIsAuto($event, gateLinkage.id)">
+                  <a-radio :value="false">关闭</a-radio>
+                  <a-radio :value="true">开启</a-radio>
+                </a-radio-group>
+                <div class="btn btn1" @click="() => openModal(false, { id: gateLinkage.id })">密码修改</div>
+              </div>
+              <div class="vent-flex-row-between auto-control mt-10px mb-10px">
+                <div class="title">风机与风门自动调节:</div>
+                <a-radio-group :value="avePressLinkage.isAuto" name="radioGroup" @change="changeIsAuto($event, avePressLinkage.id)">
+                  <a-radio :value="false">关闭</a-radio>
+                  <a-radio :value="true">开启</a-radio>
+                </a-radio-group>
+                <div class="btn btn1" @click="() => openModal(false, { id: avePressLinkage.id })">密码修改</div>
+              </div>
+              <!-- <div class="btn-box" style="text-align: center">
+            </div> -->
+            </template>
+          </ventBox1>
+        </Transition>
       </div>
+
       <ModuleCommon
-        v-for="cfg in configs"
-        :key="cfg.deviceType"
+        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="true"
+        :visible="showModules"
       />
     </div>
     <PasswordModal :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">
+    <!-- <BasicModal title="风门状态监测" :mask="false" :bodyStyle="{ height: '50px' }" style="top: 20px" :show-ok-btn="false" @register="warnRegister2">
       {{ warnModalText2 }}
     </BasicModal>
     <BasicModal
@@ -113,22 +107,25 @@
     </BasicModal>
     <BasicModal title="局扇状态监测" :mask="false" :bodyStyle="{ height: '50px' }" style="top: 420px" :show-ok-btn="false" @register="warnRegister3">
       {{ warnModalText3 }}
-    </BasicModal>
+    </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 { ref, onMounted, onUnmounted, defineProps, h } 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 { settingParam4 } from '../balancePress.data';
-  import { notification } from 'ant-design-vue';
+  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 { BasicModal, useModal } from '/@/components/Modal';
+  import { useModal } from '/@/components/Modal';
   import { connectWebSocket, onWebSocket } from '/@/hooks/web/useWebSocket';
   import { getToken } from '/@/utils/auth';
   import { useUserStore } from '/@/store/modules/user';
@@ -145,6 +142,7 @@
   const { sysOrgCode } = useGlobSetting();
 
   const loading = ref(false);
+  const showModules = ref(true);
 
   // 监测数据
   const selectData = ref();
@@ -216,17 +214,24 @@
     return result;
   }
 
-  const { avePressSetting, avePressLinkage, gateLinkage, formData, getAvePress, changePassword, linkageControl, settingControl, autoControl } =
-    usePressControl();
+  const {
+    avePressSetting,
+    avePressLinkage,
+    gateLinkage,
+    formData,
+    getAvePress,
+    changePassword,
+    linkageControl,
+    settingControl,
+    autoControl,
+    cancelControl,
+  } = usePressControl();
 
   const modalVisible = ref(false);
 
   const { configs, fetchConfigs } = useInitConfigs();
 
   const [updatePwdRegister, { openModal, closeModal, setModalProps }] = useModal();
-  const [warnRegister1, warnModal1] = useModal();
-  const [warnRegister2, warnModal2] = useModal();
-  const [warnRegister3, warnModal3] = useModal();
 
   function handleChangePassword(values) {
     setModalProps({ confirmLoading: true });
@@ -250,14 +255,14 @@
       });
     };
   }
-  function changeIsAutoControl({ target }) {
-    formData.value.isAutoControl = target.value;
+  function changeAvePressState({ target }, key) {
+    formData.value.temp = target.value;
     modalVisible.value = true;
     resolver = (password) => {
       settingControl(
         { password, id: avePressSetting.value.id },
         {
-          isAutoControl: formData.value.isAutoControl,
+          [key]: formData.value.temp,
         }
       ).finally(() => {
         modalVisible.value = false;
@@ -286,9 +291,15 @@
     resolver = null;
   }
 
-  const warnModalText1 = ref('');
-  const warnModalText2 = ref('');
-  const warnModalText3 = ref('');
+  // const [warnRegister1, warnModal1] = useModal();
+  // const [warnRegister2, warnModal2] = useModal();
+  // const [warnRegister3, warnModal3] = useModal();
+  const warnModal1 = ref();
+  const warnModal2 = ref();
+  const warnModal3 = ref();
+  // const warnModalText1 = ref('');
+  // const warnModalText2 = ref('');
+  // const warnModalText3 = ref('');
 
   // 初始化 WebSocket
   function initWebSocket() {
@@ -299,73 +310,88 @@
     const url = `${glob.wsUrl?.replace('https://', 'wss://').replace('http://', 'ws://')}/websocket/${userStore.getUserInfo.id}?token=${token}`;
     connectWebSocket(url);
     onWebSocket((data: any) => {
-      if (data.cmd === 'topic') {
-        if (data.msgTxt) {
-          const { info = '' } = JSON.parse(data.msgTxt);
-          if (info.includes('局扇')) {
-            warnModalText3.value = info;
-            warnModal3.openModal();
-          }
-          if (info.includes('风门')) {
-            warnModalText2.value = info;
-            warnModal2.openModal();
-          }
-          if (info.includes('压差')) {
-            warnModalText1.value = info;
-            warnModal1.openModal();
-          }
-        }
+      if (data.cmd !== 'topic' || data.topic !== 'warn') return;
+      if (!data.msgTxt) return;
+
+      const { info = '', type = '', avgPressLogId, date } = JSON.parse(data.msgTxt);
+      switch (type) {
+        case 'o2':
+          if (warnModal1.value) break;
+          warnModal1.value = Modal.confirm({
+            title: data.msgTitle,
+            content: h('div', { style: { color: '#fff' } }, [h('p', date), h('p', info)]),
+            centered: true,
+            okText: '下发调节指令',
+            mask: true,
+            class: 'balancePress',
+            async onOk() {
+              await autoControl(avgPressLogId);
+              warnModal1.value = null;
+            },
+            async onCancel() {
+              await cancelControl(avgPressLogId);
+              warnModal1.value = null;
+            },
+          });
+          // warnModalText1.value = info;
+          // warnModal1.openModal();
+
+          break;
+        case 'pressure':
+          // warnModalText1.value = info;
+          // warnModal1.openModal();
+          if (warnModal1.value) break;
+          warnModal1.value = Modal.confirm({
+            title: data.msgTitle,
+            content: h('div', { style: { color: '#fff' } }, [h('p', date), h('p', info)]),
+            centered: true,
+            okText: '下发调节指令',
+            mask: true,
+            class: 'balancePress',
+            async onOk() {
+              await autoControl(avgPressLogId);
+              warnModal1.value = null;
+            },
+            async onCancel() {
+              await cancelControl(avgPressLogId);
+              warnModal1.value = null;
+            },
+          });
+
+          break;
+        case 'gate':
+          if (warnModal2.value) break;
+          warnModal2.value = Modal.warn({
+            title: data.msgTitle,
+            content: info,
+            showOkBtn: false,
+            mask: true,
+            class: 'balancePress',
+            onOk: () => {
+              warnModal2.value = null;
+            },
+          });
+          break;
+        case 'fansys':
+          if (warnModal3.value) break;
+          warnModal3.value = Modal.warn({
+            title: data.msgTitle,
+            content: info,
+            showOkBtn: false,
+            mask: true,
+            class: 'balancePress',
+            style: 'top: 700px',
+            onOk: () => {
+              warnModal3.value = null;
+            },
+          });
+
+          break;
+
+        default:
+          break;
       }
     });
-
-    // setInterval(() => {
-    //   const data = [
-    //     {
-    //       cmd: 'topic',
-    //       msgTxt: `{"info":"局扇-我是局扇啊!"}`,
-    //     },
-    //     {
-    //       cmd: 'topic',
-    //       msgTxt: `{"info":"压差-我是压差啊!"}`,
-    //     },
-    //     {
-    //       cmd: 'topic',
-    //       msgTxt: `{"info":"风门-我是风门啊!"}`,
-    //     },
-    //   ][(Math.random() * 3) | 0];
-    //   if (data.cmd === 'topic') {
-    //     if (data.msgTxt) {
-    //       const { info = '' } = JSON.parse(data.msgTxt);
-    //       if (info.includes('局扇')) {
-    //         warnModalText3.value = info;
-    //         warnModal3.openModal();
-    //         // notification.warn({
-    //         //   description: info,
-    //         //   message: '警报!',
-    //         //   duration: 0,
-    //         // });
-    //       }
-    //       if (info.includes('风门')) {
-    //         warnModalText2.value = info;
-    //         warnModal2.openModal();
-    //         // notification.warn({
-    //         //   description: info,
-    //         //   message: '警报!',
-    //         //   duration: 0,
-    //         // });
-    //       }
-    //       if (info.includes('压差')) {
-    //         warnModalText1.value = info;
-    //         warnModal1.openModal();
-    //         // notification.warn({
-    //         //   description: info,
-    //         //   message: '警报!',
-    //         //   duration: 0,
-    //         // });
-    //       }
-    //     }
-    //   }
-    // }, 5000);
   }
 
   const settingFormDisabled = ref(true);
@@ -409,4 +435,33 @@
   .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>

+ 17 - 6
src/views/vent/monitorManager/balancePressMonitor/hooks/useControl.ts

@@ -1,19 +1,19 @@
 import { message } from 'ant-design-vue';
 import { get } from 'lodash-es';
 import { ref } from 'vue';
-import { submitEdit, updatePassword, validPassword, subList2, controlWindow } from '../balancePress.api';
+import { submitEdit, updatePassword, validPassword, subList2, controlWindow, cancelcontrolWindow } from '../balancePress.api';
 
 export function usePressControl() {
   /** 参数与设置、风机风门联动表单数据 */
   const formData = ref({
     /** 风机风门联动的自动调控 */
     isAuto: false,
-    /** 参数与设置的自动调控 */
-    isAutoControl: false,
+    /** 参数与设置的状态暂存字段 */
+    temp: false,
   });
   /** 参数与设置、风机风门联动的数据 */
   const avePressLinkage = ref<any>({ isAuto: false });
-  const avePressSetting = ref<any>({ isAutoControl: false });
+  const avePressSetting = ref<any>({ isAuto: false });
   /** 风门与风门联动控制 */
   const gateLinkage = ref<any>({ isAuto: false });
 
@@ -106,8 +106,18 @@ export function usePressControl() {
       });
   }
 
-  function autoControl() {
-    return controlWindow({ id: avePressSetting.value.id })
+  function autoControl(avgPressLogId) {
+    return controlWindow({ avgPressId: avePressSetting.value.id, avgPressLogId })
+      .then(() => {
+        message.success('下发成功');
+      })
+      .catch(() => {
+        message.error('下发失败');
+      });
+  }
+
+  function cancelControl(avgPressLogId) {
+    return cancelcontrolWindow({ avgPressId: avePressSetting.value.id, avgPressLogId })
       .then(() => {
         message.success('下发成功');
       })
@@ -122,6 +132,7 @@ export function usePressControl() {
     changePassword,
     getAvePress,
     autoControl,
+    cancelControl,
     avePressLinkage,
     avePressSetting,
     gateLinkage,

+ 146 - 20
src/views/vent/monitorManager/comment/GroupMonitorTable.vue

@@ -102,6 +102,104 @@
   };
 
   /** 定义table Columns */
+  // function setColumns(columnsType) {
+  //   const isCheckColumn = {
+  //     title: '',
+  //     dataIndex: 'isCheck',
+  //     width: 40,
+  //     align: 'center',
+  //     customCell: (_, index) => {
+
+  //       if (index % 3 == 0) {
+  //         return { rowSpan: 3 };
+  //       } else {
+  //         return { rowSpan: 0 };
+  //       }
+  //     },
+  //   };
+  //   const indexColumn = {
+  //     title: '序号',
+  //     dataIndex: 'key',
+  //     width: 80,
+  //     align: 'center',
+  //     customCell: (_, index) => {
+  //       if (index % 3 == 0) {
+  //         return { rowSpan: 3 };
+  //       } else {
+  //         return { rowSpan: 0 };
+  //       }
+  //     },
+  //     customRender: function ({ index }) {
+  //       return index / 3 + 1;
+  //     },
+  //   };
+  //   const runDevice = {
+  //     title: '风机',
+  //     dataIndex: 'runDevice',
+  //     width: 80,
+  //     align: 'center',
+  //   };
+
+  //   columns.value = getTableHeaderColumns(columnsType);
+  //   console.log('风机columns------------------>', columnsType);
+  //   if (columns.value && columns.value.length < 1) {
+  //     columns.value = getTableHeaderColumns(columnsType.split('_')[0] + '_monitor');
+  //   }
+
+  //   const strinstallpos = columns.value.find((item) => {
+  //     return item.dataIndex === 'strinstallpos' || item.dataIndex === 'strname';
+  //   });
+  //   if (strinstallpos) {
+  //     strinstallpos.customCell = (_, index) => {
+  //       if (index % 3 == 0) {
+  //         return { rowSpan: 3 };
+  //       } else {
+  //         return { rowSpan: 0 };
+  //       }
+  //     };
+  //   }
+  //   columns.value.forEach((item) => {
+  //     if (item.dataIndex === 'strinstallpos' || item.dataIndex === 'strname' || item.dataIndex.endsWith('_merge')) {
+  //       item.customCell = (_, index) => {
+  //         if (index % 3 == 0) {
+  //           return { rowSpan: 3 };
+  //         } else {
+  //           return { rowSpan: 0 };
+  //         }
+  //       };
+  //     }
+  //   });
+
+  //   columns.value.splice(1, 0, runDevice);
+  //   if (props.isShowSelect) {
+  //     columns.value = [isCheckColumn, indexColumn, ...columns.value];
+  //   } else {
+  //     columns.value = [indexColumn, ...columns.value];
+  //   }
+
+  //   if (props.isAction) {
+  //     columns.value = [
+  //       ...columns.value,
+  //       {
+  //         title: '操作',
+  //         dataIndex: 'operation',
+  //         width: 120,
+  //         align: 'center',
+  //         slots: { customRender: 'operation' },
+  //         customCell: (_, index) => {
+  //           if (index % 3 == 0) {
+  //             return { rowSpan: 3 };
+  //           } else {
+  //             return { rowSpan: 0 };
+  //           }
+  //         },
+  //       },
+  //     ];
+  //   }
+  //   // columns.value = [...columns.value, ...columns.value]
+  //   return columns;
+  // }
+
   function setColumns(columnsType) {
     const isCheckColumn = {
       title: '',
@@ -109,8 +207,9 @@
       width: 40,
       align: 'center',
       customCell: (_, index) => {
-        if (index % 2 == 0) {
-          return { rowSpan: 2 };
+        const columnNum = _.modalTyoe === 'lijing_3' ? 3 : 2;
+        if (_.rowIndex % columnNum == 0) {
+          return { rowSpan: columnNum };
         } else {
           return { rowSpan: 0 };
         }
@@ -122,14 +221,17 @@
       width: 80,
       align: 'center',
       customCell: (_, index) => {
-        if (index % 2 == 0) {
-          return { rowSpan: 2 };
+        debugger;
+        const columnNum = _.modalTyoe === 'lijing_3' ? 3 : 2;
+        if (_.rowIndex % columnNum == 0) {
+          return { rowSpan: columnNum };
         } else {
           return { rowSpan: 0 };
         }
       },
-      customRender: function ({ index }) {
-        return index / 2 + 1;
+      customRender: ({ text, record, index }) => {
+        const columnNum = record.modalTyoe === 'lijing_3' ? 3 : 2;
+        return record.rowIndex / columnNum + 1;
       },
     };
     const runDevice = {
@@ -150,8 +252,9 @@
     });
     if (strinstallpos) {
       strinstallpos.customCell = (_, index) => {
-        if (index % 2 == 0) {
-          return { rowSpan: 2 };
+        const columnNum = _.modalTyoe === 'lijing_3' ? 3 : 2;
+        if (_.rowIndex % columnNum == 0) {
+          return { rowSpan: columnNum };
         } else {
           return { rowSpan: 0 };
         }
@@ -160,8 +263,9 @@
     columns.value.forEach((item) => {
       if (item.dataIndex === 'strinstallpos' || item.dataIndex === 'strname' || item.dataIndex.endsWith('_merge')) {
         item.customCell = (_, index) => {
-          if (index % 2 == 0) {
-            return { rowSpan: 2 };
+          const columnNum = _.modalTyoe === 'lijing_3' ? 3 : 2;
+          if (_.rowIndex % columnNum == 0) {
+            return { rowSpan: columnNum };
           } else {
             return { rowSpan: 0 };
           }
@@ -186,8 +290,9 @@
           align: 'center',
           slots: { customRender: 'operation' },
           customCell: (_, index) => {
-            if (index % 2 == 0) {
-              return { rowSpan: 2 };
+            const columnNum = _.modalTyoe === 'lijing_3' ? 3 : 2;
+            if (_.rowIndex % columnNum == 0) {
+              return { rowSpan: columnNum };
             } else {
               return { rowSpan: 0 };
             }
@@ -226,8 +331,10 @@
       const list: unknown[] = [];
       newVal.forEach((item) => {
         const data: any = toRaw(item);
+        const modalTyoe = data.modalTyoe; ///
         const resultData1 = {};
         const resultData2 = {};
+        const resultData3 = {};
         // 将主风机、备风机的数据进行拆分
         columns.value.forEach((column) => {
           const columnKey = column.dataIndex;
@@ -235,43 +342,52 @@
             if (columnKey.startsWith('Fan')) {
               const key1 = columnKey.replace('Fan', 'Fan1');
               const key2 = columnKey.replace('Fan', 'Fan2');
+              const key3 = columnKey.replace('Fan', 'Fan3');
               if (columnKey.endsWith('_merge')) {
-                resultData1[columnKey] = data[key1] == 0 || data[key1] == null || data[key1] == undefined ? data[key2] : data[key1];
+                resultData1[columnKey] = data[key1] == 0 || data[key1] == null || data[key1] == undefined ? data[key2] : data[key1] || data[key3];
               } else {
                 if (columnKey.startsWith('FanStartStatus')) {
                   resultData1[columnKey] = data[key1];
                   resultData2[columnKey] = data[key2];
+                  resultData3[columnKey] = data[key3];
                 } else {
                   resultData1[columnKey] = data['Fan1StartStatus'] == '0' && globalConfig?.simulatedPassword ? '-' : data[key1];
                   resultData2[columnKey] = data['Fan2StartStatus'] == '0' && globalConfig?.simulatedPassword ? '-' : data[key2];
+                  resultData3[columnKey] = data['Fan3StartStatus'] == '0' && globalConfig?.simulatedPassword ? '-' : data[key3];
                 }
                 if (resultData1[columnKey] == undefined && resultData2[columnKey] == undefined) {
                   resultData1[columnKey] = data[columnKey];
                   resultData2[columnKey] = data[columnKey];
+                  resultData3[columnKey] = data[columnKey];
                 }
               }
             } else if (columnKey.startsWith('fan')) {
               const key1 = columnKey.replace('fan', 'fan1');
               const key2 = columnKey.replace('fan', 'fan2');
+              const key3 = columnKey.replace('fan', 'fan3');
               if (columnKey.endsWith('_merge')) {
-                resultData1[columnKey] = !data[key1] || data[key1] == 0 || data[key1] == null || data[key1] == undefined ? data[key2] : data[key1];
+                resultData1[columnKey] =
+                  !data[key1] || data[key1] == 0 || data[key1] == null || data[key1] == undefined ? data[key2] : data[key1] || data[key3];
               } else {
                 if (columnKey.startsWith('fanStartStatus')) {
                   resultData1[columnKey] = data[key1];
                   resultData2[columnKey] = data[key2];
+                  resultData3[columnKey] = data[key3];
                 } else {
                   resultData1[columnKey] = data['fan1StartStatus'] == '0' && globalConfig?.simulatedPassword ? '-' : data[key1];
                   resultData2[columnKey] = data['fan2StartStatus'] == '0' && globalConfig?.simulatedPassword ? '-' : data[key2];
+                  resultData3[columnKey] = data['fan3StartStatus'] == '0' && globalConfig?.simulatedPassword ? '-' : data[key3];
                 }
                 if (resultData1[columnKey] == undefined && resultData2[columnKey] == undefined) {
                   resultData1[columnKey] = data[columnKey];
                   resultData2[columnKey] = data[columnKey];
+                  resultData3[columnKey] = data[columnKey];
                 }
               }
             } else if (columnKey.endsWith('_merge')) {
               resultData1[columnKey] = data[columnKey];
             } else {
-              resultData1[columnKey] = resultData2[columnKey] = data[columnKey];
+              resultData1[columnKey] = resultData2[columnKey] = resultData3[columnKey] = data[columnKey];
             }
           }
         });
@@ -279,16 +395,26 @@
         if (props.columnsType.startsWith('fanlocal') && sysOrgCode !== 'zmhjhzmy') {
           resultData1['runDevice'] = '主机';
           resultData2['runDevice'] = '备机';
+          resultData1['rowIndex'] = 0;
+          resultData2['rowIndex'] = 1;
         } else {
           resultData1['runDevice'] = '1#风机';
           resultData2['runDevice'] = '2#风机';
+          resultData3['runDevice'] = '3#风机';
+          resultData1['modalTyoe'] = modalTyoe;
+          resultData2['modalTyoe'] = modalTyoe;
+          resultData3['modalTyoe'] = modalTyoe;
+
+          resultData1['rowIndex'] = 0;
+          resultData2['rowIndex'] = 1;
+          resultData3['rowIndex'] = 2;
+        }
+        if (modalTyoe === 'lijing_3') {
+          list.push(resultData1, resultData2, resultData3);
+        } else {
+          list.push(resultData1, resultData2);
         }
-        list.push(resultData1, resultData2);
       });
-      // if (oldVal.length < 1 && selectRowIndex.value == -1) {
-      //   // 第一次
-      //   setSelectedRowKeys(list[0]['deviceID']);
-      // }
 
       dataTableSource.value = list;
       loading.value = false;

+ 583 - 583
src/views/vent/monitorManager/comment/HistoryTable.vue

@@ -47,632 +47,632 @@
 </template>
 
 <script lang="ts" setup>
-  //ts语法
-  import { watchEffect, ref, watch, defineExpose, inject, nextTick, onMounted, computed } from 'vue';
-  import { FormSchema } from '/@/components/Form/index';
-  import { BasicTable } from '/@/components/Table';
-  import { useListPage } from '/@/hooks/system/useListPage';
-  import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
-  import { defHttp } from '/@/utils/http/axios';
-  import dayjs from 'dayjs';
-  import { getAutoScrollContainer } from '/@/utils/common/compUtils';
-  import { render } from '/@/utils/common/renderUtils';
-  import { useMethods } from '/@/hooks/system/useMethods';
-  import BarAndLine from '/@/components/chart/BarAndLine.vue';
-  import { getDictItemsByCode } from '/@/utils/dict';
-  import { get } from 'lodash-es';
-
-  const globalConfig = inject('globalConfig');
-  const props = defineProps({
-    columnsType: {
-      type: String,
-    },
-    columns: {
-      type: Array,
-      // required: true,
-      default: () => [],
-    },
-    deviceType: {
-      type: String,
-      required: true,
-    },
-    deviceListApi: {
-      type: Function,
-    },
-    deviceArr: {
-      type: Array,
-      // required: true,
-      default: () => [],
-    },
-    designScope: {
-      type: String,
-    },
-    sysId: {
-      type: String,
-    },
-    deviceId: {
-      type: String,
-    },
-    scroll: {
-      type: Object,
-      default: { y: 0 },
-    },
-    formSchemas: {
-      type: Array<FormSchema>,
-      default: () => [],
-    },
-    /** 仅展示已绑定设备,选择是则从系统中获取sysId下已绑定设备。仅能查询到已绑定设备的历史数据 */
-    onlyBounedDevices: {
-      type: Boolean,
-      default: false,
-    },
-    showHistoryCurve: {
-      type: Boolean,
-      default: false,
-    },
+//ts语法
+import { watchEffect, ref, watch, defineExpose, inject, nextTick, onMounted, computed } from 'vue';
+import { FormSchema } from '/@/components/Form/index';
+import { BasicTable } from '/@/components/Table';
+import { useListPage } from '/@/hooks/system/useListPage';
+import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
+import { defHttp } from '/@/utils/http/axios';
+import dayjs from 'dayjs';
+import { getAutoScrollContainer } from '/@/utils/common/compUtils';
+import { render } from '/@/utils/common/renderUtils';
+import { useMethods } from '/@/hooks/system/useMethods';
+import BarAndLine from '/@/components/chart/BarAndLine.vue';
+import { getDictItemsByCode } from '/@/utils/dict';
+import { get } from 'lodash-es';
+
+const globalConfig = inject('globalConfig');
+const props = defineProps({
+  columnsType: {
+    type: String,
+  },
+  columns: {
+    type: Array,
+    // required: true,
+    default: () => [],
+  },
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceListApi: {
+    type: Function,
+  },
+  deviceArr: {
+    type: Array,
+    // required: true,
+    default: () => [],
+  },
+  designScope: {
+    type: String,
+  },
+  sysId: {
+    type: String,
+  },
+  deviceId: {
+    type: String,
+  },
+  scroll: {
+    type: Object,
+    default: { y: 0 },
+  },
+  formSchemas: {
+    type: Array<FormSchema>,
+    default: () => [],
+  },
+  /** 仅展示已绑定设备,选择是则从系统中获取sysId下已绑定设备。仅能查询到已绑定设备的历史数据 */
+  onlyBounedDevices: {
+    type: Boolean,
+    default: false,
+  },
+  showHistoryCurve: {
+    type: Boolean,
+    default: false,
+  },
+});
+const getDeviceListApi = (params) => defHttp.post({ url: '/monitor/device', params });
+const historyTable = ref();
+const loading = ref(false);
+const stationType = ref('plc1');
+const dataSource = ref([]);
+const intervalMap = new Map([
+  ['1', '1s'],
+  ['2', '5s'],
+  ['3', '10s'],
+  ['4', '30s'],
+  ['5', '1m'],
+  ['6', '10m'],
+  ['7', '30m'],
+  ['8', '1h'],
+  ['9', '1d'],
+]);
+
+const getExportXlsUrl = () => {
+  if (stationType.value !== 'redis') {
+    return '/safety/ventanalyMonitorData/export/historydata';
+  } else {
+    return '/monitor/history/exportHistoryData';
+  }
+};
+const emit = defineEmits(['change']);
+
+const historyType = ref('');
+const deviceKide = ref('');
+const columns = ref([]);
+let deviceOptions = ref([]);
+const deviceTypeStr = ref('');
+const deviceTypeName = ref('');
+const deviceType = ref('');
+const chartsColumns = ref([]);
+loading.value = true;
+
+const selectedOption = computed<Record<string, any> | undefined>(() => {
+  let idval: string | undefined = getForm()?.getFieldsValue()?.gdeviceids;
+  if (VENT_PARAM.historyIsMultiple && idval) {
+    const arr = idval.split(',');
+    idval = arr[arr.length - 1];
+  }
+  return deviceOptions.value.find((e: any) => {
+    return e.value === idval;
   });
-  const getDeviceListApi = (params) => defHttp.post({ url: '/monitor/device', params });
-  const historyTable = ref();
-  const loading = ref(false);
-  const stationType = ref('plc1');
-  const dataSource = ref([]);
-  const intervalMap = new Map([
-    ['1', '1s'],
-    ['2', '5s'],
-    ['3', '10s'],
-    ['4', '30s'],
-    ['5', '1m'],
-    ['6', '10m'],
-    ['7', '30m'],
-    ['8', '1h'],
-    ['9', '1d'],
-  ]);
-
-  const getExportXlsUrl = () => {
-    if (stationType.value !== 'redis') {
-      return '/safety/ventanalyMonitorData/export/historydata';
-    } else {
-      return '/monitor/history/exportHistoryData';
-    }
-  };
-  const emit = defineEmits(['change']);
-
-  const historyType = ref('');
-  const deviceKide = ref('');
-  const columns = ref([]);
-  let deviceOptions = ref([]);
-  const deviceTypeStr = ref('');
-  const deviceTypeName = ref('');
-  const deviceType = ref('');
-  const chartsColumns = ref([]);
-  loading.value = true;
-
-  const selectedOption = computed<Record<string, any> | undefined>(() => {
-    let idval: string | undefined = getForm()?.getFieldsValue()?.gdeviceids;
-    if (VENT_PARAM.historyIsMultiple && idval) {
-      const arr = idval.split(',');
-      idval = arr[arr.length - 1];
+});
+
+watch(
+  () => {
+    return props.columnsType;
+  },
+  async (newVal) => {
+    if (!newVal) return;
+    deviceKide.value = newVal;
+    if (historyTable.value) {
+      getForm().resetFields();
+      // getForm().updateSchema();
+      // getForm();
     }
-    return deviceOptions.value.find((e: any) => {
-      return e.value === idval;
+    dataSource.value = [];
+    // const column = getTableHeaderColumns(newVal.includes('_history') ? newVal : newVal + '_history');
+    // if (column && column.length < 1) {
+    //   const arr = newVal.split('_');
+    //   console.log('历史记录列表表头------------>', arr[0] + '_monitor');
+    //   columns.value = getTableHeaderColumns(arr[0] + '_history');
+    //   if (columns.value.length < 1) {
+    //     if (historyType.value) {
+    //       columns.value = getTableHeaderColumns(historyType.value + '_history');
+    //     }
+    //   }
+    // } else {
+    //   columns.value = column;
+    // }
+    await getDeviceList();
+    nextTick(() => {
+      getDataSource();
     });
-  });
-
-  watch(
-    () => {
-      return props.columnsType;
-    },
-    async (newVal) => {
-      if (!newVal) return;
-      deviceKide.value = newVal;
-      if (historyTable.value) {
-        getForm().resetFields();
-        // getForm().updateSchema();
-        // getForm();
-      }
-      dataSource.value = [];
-      // const column = getTableHeaderColumns(newVal.includes('_history') ? newVal : newVal + '_history');
-      // if (column && column.length < 1) {
-      //   const arr = newVal.split('_');
-      //   console.log('历史记录列表表头------------>', arr[0] + '_monitor');
-      //   columns.value = getTableHeaderColumns(arr[0] + '_history');
-      //   if (columns.value.length < 1) {
-      //     if (historyType.value) {
-      //       columns.value = getTableHeaderColumns(historyType.value + '_history');
-      //     }
-      //   }
-      // } else {
-      //   columns.value = column;
-      // }
-      await getDeviceList();
-      nextTick(() => {
-        getDataSource();
-      });
-
-      if (historyTable.value) reload();
-    },
-    {
-      immediate: true,
-    }
-  );
-
-  watch(historyType, (type) => {
-    if (!type) return;
-    // if (historyTable.value) getForm().resetFields()
-
-    const column = getTableHeaderColumns(type.includes('_history') ? type : type + '_history');
-    if (column && column.length < 1) {
-      const arr = type.split('_');
-      columns.value = getTableHeaderColumns(arr[0] + '_history');
-    } else {
-      columns.value = column;
-    }
-    setColumns(columns.value);
-  });
-
-  const showCurve = ref(false);
-
-  // 是否显示历史曲线,在devices_shows_history_curve字典里可以配置哪些设备类型需要显示曲线
-  // 字典内的字段可以是前缀,例如fanlocal之于fanlocal_normal
-  // 安全监控设备需要更多的配置,除去配置safetymonitor,还需要配置哪些安全监控设备需要曲线
-  // 因此可以配置例如A1001的dataTypeName代码(可以查看真实数据参考)
-  function calcShowCurveValue() {
-    const historyCurveDicts = getDictItemsByCode('devices_shows_history_curve') || [];
-    const findDict = (str) => historyCurveDicts.some(({ value }) => str.startsWith(value));
-
-    if (!props.showHistoryCurve) return false;
-    const dt = props.deviceType; // 依赖项
 
-    if (!findDict(dt)) return false;
-    if (!dt.startsWith('safetymonitor')) return true;
-
-    // 和字典的设备类型匹配后,如果是安全监控设备,需要额外的匹配安全监控类型
-    const dtns = get(selectedOption.value, 'readData.dataTypeName', ''); // 依赖项
-    return findDict(dtns);
+    if (historyTable.value) reload();
+  },
+  {
+    immediate: true,
+  }
+);
+
+watch(historyType, (type) => {
+  if (!type) return;
+  // if (historyTable.value) getForm().resetFields()
+
+  const column = getTableHeaderColumns(type.includes('_history') ? type : type + '_history');
+  if (column && column.length < 1) {
+    const arr = type.split('_');
+    columns.value = getTableHeaderColumns(arr[0] + '_history');
+  } else {
+    columns.value = column;
+  }
+  setColumns(columns.value);
+});
+
+const showCurve = ref(false);
+
+// 是否显示历史曲线,在devices_shows_history_curve字典里可以配置哪些设备类型需要显示曲线
+// 字典内的字段可以是前缀,例如fanlocal之于fanlocal_normal
+// 安全监控设备需要更多的配置,除去配置safetymonitor,还需要配置哪些安全监控设备需要曲线
+// 因此可以配置例如A1001的dataTypeName代码(可以查看真实数据参考)
+function calcShowCurveValue() {
+  const historyCurveDicts = getDictItemsByCode('devices_shows_history_curve') || [];
+  const findDict = (str) => historyCurveDicts.some(({ value }) => str.startsWith(value));
+
+  if (!props.showHistoryCurve) return false;
+  const dt = props.deviceType; // 依赖项
+
+  if (!findDict(dt)) return false;
+  if (!dt.startsWith('safetymonitor')) return true;
+
+  // 和字典的设备类型匹配后,如果是安全监控设备,需要额外的匹配安全监控类型
+  const dtns = get(selectedOption.value, 'readData.dataTypeName', ''); // 依赖项
+  return findDict(dtns);
+}
+
+function initHistoryCurveColumns() {
+  if (!props.showHistoryCurve) return;
+  const arr = historyType.value.split('_');
+  // 没错,又是安全监控。安全监控的单位无法一次定好,所以根据返回的数据协定单位
+  if (props.deviceType.startsWith('safetymonitor')) {
+    chartsColumns.value = getTableHeaderColumns(arr[0] + '_chart').map((e) => {
+      const unit = get(selectedOption.value, 'readData.unit', e.unit);
+      return {
+        ...e,
+        unit: unit,
+        seriesName: unit,
+      };
+    });
+  } else {
+    chartsColumns.value = getTableHeaderColumns(arr[0] + '_chart');
+  }
+}
+
+const tableScroll = computed(() => {
+  if (props.scroll.y && showCurve.value) return { y: props.scroll.y - 450 };
+  if (props.scroll.y) return { y: props.scroll.y - 100 };
+  return {};
+});
+
+// watch(stationType, (type) => {
+//   if (type) {
+//     nextTick(() => {
+//       getDataSource();
+//     });
+//   }
+// });
+
+watch(
+  () => props.deviceId,
+  async () => {
+    await getForm().setFieldsValue({});
+    await getDeviceList();
+  }
+);
+
+/** 获取可供查询历史数据的设备列表 */
+async function getDeviceList() {
+  // if (props.deviceType.split('_')[1] && props.deviceType.split('_')[1] === 'history') return;
+  let result;
+  let response;
+  if (props.onlyBounedDevices) {
+    response = await getDeviceListApi({
+      systemID: props.sysId,
+      devicetype: 'sys',
+    }).then(({ msgTxt }) => {
+      return { msgTxt: msgTxt.filter((e) => e.type === props.deviceType) };
+    });
+  } else if (props.sysId) {
+    response = await getDeviceListApi({
+      sysId: props.sysId,
+      devicetype: props.deviceType.startsWith('vehicle') ? 'location_normal' : props.deviceType,
+      pageSize: 10000,
+    });
+  } else if (props.deviceListApi) {
+    response = await props.deviceListApi();
+  } else {
+    response = await getDeviceListApi({ devicetype: props.deviceType, pageSize: 10000 });
   }
 
-  function initHistoryCurveColumns() {
-    if (!props.showHistoryCurve) return;
-    const arr = historyType.value.split('_');
-    // 没错,又是安全监控。安全监控的单位无法一次定好,所以根据返回的数据协定单位
-    if (props.deviceType.startsWith('safetymonitor')) {
-      chartsColumns.value = getTableHeaderColumns(arr[0] + '_chart').map((e) => {
-        const unit = get(selectedOption.value, 'readData.unit', e.unit);
-        return {
-          ...e,
-          unit: unit,
-          seriesName: unit,
-        };
-      });
-    } else {
-      chartsColumns.value = getTableHeaderColumns(arr[0] + '_chart');
-    }
+  // 处理不同格式的数据
+  if (response['records'] && response['records'].length > 0) {
+    result = response['records'];
+  } else if (response['msgTxt'] && response['msgTxt'][0] && response['msgTxt'][0]['datalist']) {
+    result = response['msgTxt'][0]['datalist'];
+  }
+  if (response['msgTxt'] && response['msgTxt'][0]) {
+    deviceTypeName.value = response['msgTxt'][0]['typeName'];
+    deviceType.value = response['msgTxt'][0]['type'];
   }
 
-  const tableScroll = computed(() => {
-    if (props.scroll.y && showCurve.value) return { y: props.scroll.y - 450 };
-    if (props.scroll.y) return { y: props.scroll.y - 100 };
-    return {};
-  });
+  if (result) {
+    deviceOptions.value = [];
+    deviceOptions.value = result.map((item, index) => {
+      return {
+        label: item['strinstallpos'],
+        value: item['id'] || item['deviceID'],
+        strtype: item['strtype'] || item['deviceType'],
+        strinstallpos: item['strinstallpos'],
+        devicekind: item['devicekind'],
+        stationtype: item['stationtype'],
+        readData: item['readData'],
+      };
+    });
 
-  // watch(stationType, (type) => {
-  //   if (type) {
-  //     nextTick(() => {
-  //       getDataSource();
-  //     });
-  //   }
-  // });
-
-  watch(
-    () => props.deviceId,
-    async () => {
-      await getForm().setFieldsValue({});
-      await getDeviceList();
-    }
-  );
-
-  /** 获取可供查询历史数据的设备列表 */
-  async function getDeviceList() {
-    // if (props.deviceType.split('_')[1] && props.deviceType.split('_')[1] === 'history') return;
-    let result;
-    let response;
-    if (props.onlyBounedDevices) {
-      response = await getDeviceListApi({
-        systemID: props.sysId,
-        devicetype: 'sys',
-      }).then(({ msgTxt }) => {
-        return { msgTxt: msgTxt.filter((e) => e.type === props.deviceType) };
-      });
-    } else if (props.sysId) {
-      response = await getDeviceListApi({
-        sysId: props.sysId,
-        devicetype: props.deviceType.startsWith('vehicle') ? 'location_normal' : props.deviceType,
-        pageSize: 10000,
-      });
-    } else if (props.deviceListApi) {
-      response = await props.deviceListApi();
+    stationType.value = deviceOptions.value[0]['stationtype'];
+    if (props.deviceType.startsWith('vehicle')) {
+      historyType.value = 'vehicle';
     } else {
-      response = await getDeviceListApi({ devicetype: props.deviceType, pageSize: 10000 });
+      historyType.value = deviceOptions.value[0]['strtype'] || deviceOptions.value[0]['devicekind'];
     }
 
-    // 处理不同格式的数据
-    if (response['records'] && response['records'].length > 0) {
-      result = response['records'];
-    } else if (response['msgTxt'] && response['msgTxt'][0] && response['msgTxt'][0]['datalist']) {
-      result = response['msgTxt'][0]['datalist'];
-    }
-    if (response['msgTxt'] && response['msgTxt'][0]) {
-      deviceTypeName.value = response['msgTxt'][0]['typeName'];
-      deviceType.value = response['msgTxt'][0]['type'];
-    }
-
-    if (result) {
-      deviceOptions.value = [];
-      deviceOptions.value = result.map((item, index) => {
-        return {
-          label: item['strinstallpos'],
-          value: item['id'] || item['deviceID'],
-          strtype: item['strtype'] || item['deviceType'],
-          strinstallpos: item['strinstallpos'],
-          devicekind: item['devicekind'],
-          stationtype: item['stationtype'],
-          readData: item['readData'],
-        };
-      });
-
-      stationType.value = deviceOptions.value[0]['stationtype'];
-      if (props.deviceType.startsWith('vehicle')) {
-        historyType.value = 'vehicle';
-      } else {
-        historyType.value = deviceOptions.value[0]['strtype'] || deviceOptions.value[0]['devicekind'];
-      }
-
-      /** 此处使用nextTick是由于可能表单暂未更新,而下面的方法依赖表单项 */
-      nextTick(() => {
-        showCurve.value = calcShowCurveValue();
-        initHistoryCurveColumns();
-      });
-    }
-    if (VENT_PARAM.historyIsMultiple) {
-      await getForm().setFieldsValue({
-        gdeviceids: [props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : ''],
-      });
-      await getForm().updateSchema({
-        field: 'gdeviceids',
-        componentProps: {
-          mode: 'multiple',
-          maxTagCount: 'responsive',
-        },
-      });
-    } else {
-      await getForm().setFieldsValue({
-        gdeviceids: props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : '',
-      });
-      await getForm().updateSchema({
-        field: 'gdeviceids',
-      });
-    }
+    /** 此处使用nextTick是由于可能表单暂未更新,而下面的方法依赖表单项 */
+    nextTick(() => {
+      showCurve.value = calcShowCurveValue();
+      initHistoryCurveColumns();
+    });
   }
-
-  function resetFormParam() {
-    const formData = getForm().getFieldsValue();
-    const pagination = getPaginationRef();
-    formData['pageNo'] = pagination['current'];
-    formData['pageSize'] = pagination['pageSize'];
-    formData['column'] = 'createTime';
-    if (stationType.value !== 'redis' && deviceOptions.value[0]) {
-      formData['strtype'] = deviceTypeStr.value
-        ? deviceTypeStr.value
-        : deviceOptions.value[0]['strtype']
-        ? deviceOptions.value[0]['strtype']
-        : props.deviceType + '*';
-      if (props.sysId) {
-        formData['sysId'] = props.sysId;
-      }
-      return formData;
-    } else {
-      const params = {
-        pageNum: pagination['current'],
-        pageSize: pagination['pageSize'],
-        column: pagination['createTime'],
-        startTime: formData['ttime_begin'],
-        endTime: formData['ttime_end'],
-        deviceId: formData['gdeviceids'],
-        strtype: props.deviceType + '*',
-        sysId: props.sysId,
-        interval: intervalMap.get(formData['skip']) ? intervalMap.get(formData['skip']) : '1h',
-        isEmployee: props.deviceType.startsWith('vehicle') ? false : true,
-      };
-      return params;
+  if (VENT_PARAM.historyIsMultiple) {
+    await getForm().setFieldsValue({
+      gdeviceids: [props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : ''],
+    });
+    await getForm().updateSchema({
+      field: 'gdeviceids',
+      componentProps: {
+        mode: 'multiple',
+        maxTagCount: 'responsive',
+      },
+    });
+  } else {
+    await getForm().setFieldsValue({
+      gdeviceids: props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : '',
+    });
+    await getForm().updateSchema({
+      field: 'gdeviceids',
+    });
+  }
+}
+
+function resetFormParam() {
+  const formData = getForm().getFieldsValue();
+  const pagination = getPaginationRef();
+  formData['pageNo'] = pagination['current'];
+  formData['pageSize'] = pagination['pageSize'];
+  formData['column'] = 'createTime';
+  if (stationType.value !== 'redis' && deviceOptions.value[0]) {
+    formData['strtype'] = deviceTypeStr.value
+      ? deviceTypeStr.value
+      : deviceOptions.value[0]['strtype']
+      ? deviceOptions.value[0]['strtype']
+      : props.deviceType + '*';
+    if (props.sysId) {
+      formData['sysId'] = props.sysId;
     }
+    return formData;
+  } else {
+    const params = {
+      pageNum: pagination['current'],
+      pageSize: pagination['pageSize'],
+      column: pagination['createTime'],
+      startTime: formData['ttime_begin'],
+      endTime: formData['ttime_end'],
+      deviceId: formData['gdeviceids'],
+      strtype: props.deviceType + '*',
+      sysId: props.sysId,
+      interval: intervalMap.get(formData['skip']) ? intervalMap.get(formData['skip']) : '1h',
+      isEmployee: props.deviceType.startsWith('vehicle') ? false : true,
+    };
+    return params;
   }
-
-  async function getDataSource() {
-    dataSource.value = [];
-    setLoading(true);
-    const params = await resetFormParam();
-    if (stationType.value !== 'redis') {
-      const result = await defHttp.get({ url: '/safety/ventanalyMonitorData/listdays', params: params });
-      setPagination({ total: Math.abs(result['datalist']['total']) || 0 });
-      if (result['datalist']['records'].length > 0) {
-        dataSource.value = result['datalist']['records'].map((item: any) => {
-          return Object.assign(item, item['readData']);
-        });
-      } else {
-        dataSource.value = [];
-      }
+}
+
+async function getDataSource() {
+  dataSource.value = [];
+  setLoading(true);
+  const params = await resetFormParam();
+  if (stationType.value !== 'redis') {
+    const result = await defHttp.get({ url: '/safety/ventanalyMonitorData/listdays', params: params });
+    setPagination({ total: Math.abs(result['datalist']['total']) || 0 });
+    if (result['datalist']['records'].length > 0) {
+      dataSource.value = result['datalist']['records'].map((item: any) => {
+        return Object.assign(item, item['readData']);
+      });
     } else {
-      const result = await defHttp.post({ url: '/monitor/history/getHistoryData', params: params });
-      setPagination({ total: Math.abs(result['total']) || 0 });
-      dataSource.value = result['records'] || [];
+      dataSource.value = [];
     }
-    setLoading(false);
+  } else {
+    const result = await defHttp.post({ url: '/monitor/history/getHistoryData', params: params });
+    setPagination({ total: Math.abs(result['total']) || 0 });
+    dataSource.value = result['records'] || [];
   }
-
-  // 列表页面公共参数、方法
-  const { tableContext, onExportXls, onExportXlsPost } = useListPage({
-    tableProps: {
-      // api: list,
-      columns: props.columnsType ? columns : (props.columns as any[]),
-      canResize: true,
-      showTableSetting: false,
-      showActionColumn: false,
-      bordered: false,
-      size: 'small',
-      showIndexColumn: true,
-      tableLayout: 'auto',
-      formConfig: {
-        labelAlign: 'left',
-        labelWidth: 80,
-        showAdvancedButton: false,
-        showSubmitButton: false,
-        showResetButton: false,
-        baseColProps: {
-          xs: 24,
-          sm: 24,
-          md: 24,
-          lg: 9,
-          xl: 7,
-          xxl: 4,
-        },
-        schemas:
-          props.formSchemas.length > 0
-            ? props.formSchemas
-            : [
-                {
-                  field: 'ttime_begin',
-                  label: '开始时间',
-                  component: 'DatePicker',
-                  defaultValue: dayjs().startOf('date'),
-                  required: true,
-                  componentProps: {
-                    showTime: true,
-                    valueFormat: 'YYYY-MM-DD HH:mm:ss',
-                    getPopupContainer: getAutoScrollContainer,
-                  },
-                  colProps: {
-                    span: 4,
-                  },
+  setLoading(false);
+}
+
+// 列表页面公共参数、方法
+const { tableContext, onExportXls, onExportXlsPost } = useListPage({
+  tableProps: {
+    // api: list,
+    columns: props.columnsType ? columns : (props.columns as any[]),
+    canResize: true,
+    showTableSetting: false,
+    showActionColumn: false,
+    bordered: false,
+    size: 'small',
+    showIndexColumn: true,
+    tableLayout: 'auto',
+    formConfig: {
+      labelAlign: 'left',
+      labelWidth: 80,
+      showAdvancedButton: false,
+      showSubmitButton: false,
+      showResetButton: false,
+      baseColProps: {
+        xs: 24,
+        sm: 24,
+        md: 24,
+        lg: 9,
+        xl: 7,
+        xxl: 4,
+      },
+      schemas:
+        props.formSchemas.length > 0
+          ? props.formSchemas
+          : [
+              {
+                field: 'ttime_begin',
+                label: '开始时间',
+                component: 'DatePicker',
+                defaultValue: dayjs().startOf('date'),
+                required: true,
+                componentProps: {
+                  showTime: true,
+                  valueFormat: 'YYYY-MM-DD HH:mm:ss',
+                  getPopupContainer: getAutoScrollContainer,
+                },
+                colProps: {
+                  span: 4,
+                },
+              },
+              {
+                field: 'ttime_end',
+                label: '结束时间',
+                component: 'DatePicker',
+                defaultValue: dayjs(),
+                required: true,
+                componentProps: {
+                  showTime: true,
+                  valueFormat: 'YYYY-MM-DD HH:mm:ss',
+                  getPopupContainer: getAutoScrollContainer,
                 },
-                {
-                  field: 'ttime_end',
-                  label: '结束时间',
-                  component: 'DatePicker',
-                  defaultValue: dayjs(),
-                  required: true,
-                  componentProps: {
-                    showTime: true,
-                    valueFormat: 'YYYY-MM-DD HH:mm:ss',
-                    getPopupContainer: getAutoScrollContainer,
+                colProps: {
+                  span: 4,
+                },
+              },
+              {
+                label: computed(() => `${deviceKide.value.startsWith('location') ? '查询人员' : '查询设备'}`),
+                field: 'gdeviceids',
+                component: 'Select',
+                required: true,
+                componentProps: {
+                  showSearch: true,
+                  filterOption: (input: string, option: any) => {
+                    return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
                   },
-                  colProps: {
-                    span: 4,
+                  options: deviceOptions,
+                  onChange: (e, option) => {
+                    if (option && (option['strinstallpos'] || option['strtype'] || option['devicekind'])) {
+                      historyType.value = option['strtype'] || option['devicekind'];
+                    }
+                    if (option['strtype']) {
+                      deviceTypeStr.value = option['strtype'];
+                    }
+                    stationType.value = option['stationtype'];
+                    nextTick(() => {
+                      showCurve.value = calcShowCurveValue();
+                      initHistoryCurveColumns();
+                      getDataSource();
+                    });
                   },
                 },
-                {
-                  label: computed(() => `${deviceKide.value.startsWith('location') ? '查询人员' : '查询设备'}`),
-                  field: 'gdeviceids',
-                  component: 'Select',
-                  required: true,
-                  componentProps: {
-                    showSearch: true,
-                    filterOption: (input: string, option: any) => {
-                      return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
+                colProps: {
+                  span: 5,
+                },
+              },
+              {
+                label: '间隔时间',
+                field: 'skip',
+                component: 'Select',
+                defaultValue: '8',
+                componentProps: {
+                  options: [
+                    {
+                      label: '1秒',
+                      value: '1',
                     },
-                    options: deviceOptions,
-                    onChange: (e, option) => {
-                      if (option && (option['strinstallpos'] || option['strtype'] || option['devicekind'])) {
-                        historyType.value = option['strtype'] || option['devicekind'];
-                      }
-                      if (option['strtype']) {
-                        deviceTypeStr.value = option['strtype'];
-                      }
-                      stationType.value = option['stationtype'];
-                      nextTick(() => {
-                        showCurve.value = calcShowCurveValue();
-                        initHistoryCurveColumns();
-                        getDataSource();
-                      });
+                    {
+                      label: '5秒',
+                      value: '2',
                     },
-                  },
-                  colProps: {
-                    span: 5,
-                  },
+                    {
+                      label: '10秒',
+                      value: '3',
+                    },
+                    {
+                      label: '30秒',
+                      value: '4',
+                    },
+                    {
+                      label: '1分钟',
+                      value: '5',
+                    },
+                    {
+                      label: '10分钟',
+                      value: '6',
+                    },
+                    {
+                      label: '30分钟',
+                      value: '7',
+                    },
+                    {
+                      label: '1小时',
+                      value: '8',
+                    },
+                    {
+                      label: '1天',
+                      value: '9',
+                    },
+                  ],
                 },
-                {
-                  label: '间隔时间',
-                  field: 'skip',
-                  component: 'Select',
-                  defaultValue: '8',
-                  componentProps: {
-                    options: [
-                      {
-                        label: '1秒',
-                        value: '1',
-                      },
-                      {
-                        label: '5秒',
-                        value: '2',
-                      },
-                      {
-                        label: '10秒',
-                        value: '3',
-                      },
-                      {
-                        label: '30秒',
-                        value: '4',
-                      },
-                      {
-                        label: '1分钟',
-                        value: '5',
-                      },
-                      {
-                        label: '10分钟',
-                        value: '6',
-                      },
-                      {
-                        label: '30分钟',
-                        value: '7',
-                      },
-                      {
-                        label: '1小时',
-                        value: '8',
-                      },
-                      {
-                        label: '1天',
-                        value: '9',
-                      },
-                    ],
-                  },
-                  colProps: {
-                    span: 3,
-                  },
+                colProps: {
+                  span: 3,
                 },
-              ],
-        // fieldMapToTime: [['tickectDate', ['ttime_begin', 'ttime_end'], '']],
-      },
-      // fetchSetting: {
-      //   listField: 'datalist',
-      //   totalField: 'datalist.total',
-      // },
-      pagination: {
-        current: 1,
-        pageSize: 10,
-        pageSizeOptions: ['10', '30', '50', '100'],
-        showQuickJumper: false,
-      },
-      beforeFetch() {
-        const newParams = { ...resetFormParam() };
-        return newParams;
-      },
-      // afterFetch(result) {
-      //   const resultItems = result['records'];
-      //   resultItems.map((item) => {
-      //     Object.assign(item, item['readData']);
-      //   });
-      //   console.log('result---------------->', result);
-      //   return resultItems;
-      // },
+              },
+            ],
+      // fieldMapToTime: [['tickectDate', ['ttime_begin', 'ttime_end'], '']],
     },
-    exportConfig: {
-      name: '设备历史列表',
-      url: getExportXlsUrl,
+    // fetchSetting: {
+    //   listField: 'datalist',
+    //   totalField: 'datalist.total',
+    // },
+    pagination: {
+      current: 1,
+      pageSize: 10,
+      pageSizeOptions: ['10', '30', '50', '100'],
+      showQuickJumper: false,
     },
-  });
-
-  //注册table数据
-  const [registerTable, { reload, setLoading, getForm, setColumns, getPaginationRef, setPagination }] = tableContext;
+    beforeFetch() {
+      const newParams = { ...resetFormParam() };
+      return newParams;
+    },
+    // afterFetch(result) {
+    //   const resultItems = result['records'];
+    //   resultItems.map((item) => {
+    //     Object.assign(item, item['readData']);
+    //   });
+    //   console.log('result---------------->', result);
+    //   return resultItems;
+    // },
+  },
+  exportConfig: {
+    name: '设备历史列表',
+    url: getExportXlsUrl,
+  },
+});
+
+//注册table数据
+const [registerTable, { reload, setLoading, getForm, setColumns, getPaginationRef, setPagination }] = tableContext;
+
+function onExportXlsFn() {
+  const params = resetFormParam();
+  // 判断时间间隔和查询时间区间,数据量下载大时进行提示
+  if (stationType.value !== 'redis') {
+    return onExportXls(params);
+  } else {
+    return onExportXlsPost(params);
+  }
+}
 
-  function onExportXlsFn() {
-    const params = resetFormParam();
-    // 判断时间间隔和查询时间区间,数据量下载大时进行提示
-    if (stationType.value !== 'redis') {
-      return onExportXls(params);
-    } else {
-      return onExportXlsPost(params);
-    }
+watchEffect(() => {
+  if (historyTable.value && dataSource) {
+    const data = dataSource.value || [];
+    emit('change', data);
   }
+});
 
-  watchEffect(() => {
-    if (historyTable.value && dataSource) {
-      const data = dataSource.value || [];
-      emit('change', data);
-    }
-  });
+onMounted(async () => {
+  await getDeviceList();
+  if (deviceOptions.value[0]) {
+    nextTick(async () => {
+      await getDataSource();
+    });
+  }
 
-  onMounted(async () => {
-    await getDeviceList();
+  watch([() => getPaginationRef()['current'], () => getPaginationRef()['pageSize']], async () => {
     if (deviceOptions.value[0]) {
-      nextTick(async () => {
-        await getDataSource();
-      });
-    }
-
-    watch([() => getPaginationRef()['current'], () => getPaginationRef()['pageSize']], async () => {
       if (deviceOptions.value[0]) {
-        if (deviceOptions.value[0]) {
-          await getDataSource();
-        }
+        await getDataSource();
       }
-    });
+    }
   });
-  defineExpose({ setLoading });
+});
+defineExpose({ setLoading });
 </script>
 
 <style scoped lang="less">
-  @import '/@/design/theme.less';
-
-  :deep(.@{ventSpace}-table-body) {
-    height: auto !important;
-  }
-  :deep(.zxm-picker) {
-    height: 30px !important;
-  }
-  .history-table {
-    width: 100%;
-    :deep(.jeecg-basic-table-form-container) {
-      .@{ventSpace}-form {
-        padding: 0 !important;
-        border: none !important;
-        margin-bottom: 0 !important;
-        .@{ventSpace}-picker,
-        .@{ventSpace}-select-selector {
-          width: 100% !important;
-          height: 100%;
-          background: #00000017;
-          border: 1px solid #b7b7b7;
-          input,
-          .@{ventSpace}-select-selection-item,
-          .@{ventSpace}-picker-suffix {
-            color: #fff;
-          }
-          .@{ventSpace}-select-selection-placeholder {
-            color: #ffffffaa;
-          }
+@import '/@/design/theme.less';
+
+:deep(.@{ventSpace}-table-body) {
+  height: auto !important;
+}
+:deep(.zxm-picker) {
+  height: 30px !important;
+}
+.history-table {
+  width: 100%;
+  :deep(.jeecg-basic-table-form-container) {
+    .@{ventSpace}-form {
+      padding: 0 !important;
+      border: none !important;
+      margin-bottom: 0 !important;
+      .@{ventSpace}-picker,
+      .@{ventSpace}-select-selector {
+        width: 100% !important;
+        height: 100%;
+        background: #00000017;
+        border: 1px solid #b7b7b7;
+        input,
+        .@{ventSpace}-select-selection-item,
+        .@{ventSpace}-picker-suffix {
+          color: #fff;
+        }
+        .@{ventSpace}-select-selection-placeholder {
+          color: #ffffffaa;
         }
-      }
-      .@{ventSpace}-table-title {
-        min-height: 0 !important;
       }
     }
-    .pagination-box {
-      display: flex;
-      justify-content: flex-end;
-      align-items: center;
-      .page-num {
-        border: 1px solid #0090d8;
-        padding: 4px 8px;
-        margin-right: 5px;
-        color: #0090d8;
-      }
-      .btn {
-        margin-right: 10px;
-      }
+    .@{ventSpace}-table-title {
+      min-height: 0 !important;
     }
   }
-
-  .history-chart {
-    background-color: #0090d822;
-    margin: 0 10px;
+  .pagination-box {
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+    .page-num {
+      border: 1px solid #0090d8;
+      padding: 4px 8px;
+      margin-right: 5px;
+      color: #0090d8;
+    }
+    .btn {
+      margin-right: 10px;
+    }
   }
+}
+
+.history-chart {
+  background-color: #0090d822;
+  margin: 0 10px;
+}
 </style>

+ 593 - 0
src/views/vent/monitorManager/comment/HistoryTableChart.vue

@@ -0,0 +1,593 @@
+<template>
+  <div class="" v-if="loading">
+    <div class="charts-container">
+      <a-form
+        class="form-container"
+        :model="historyParams"
+        layout="inline"
+        :label-col="{ style: { width: '100px' } }"
+        :wrapper-col="{ span: 8 }"
+        autocomplete="off"
+        @submit.prevent="getDataSource"
+      >
+        <a-form-item label="查询设备">
+          <a-select v-model:value="historyParams.selectedDeviceId" style="width: 200px">
+            <a-select-option v-for="d in deviceOptions" :key="d.label" :value="d.value">{{ d.label }}</a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="间隔时间">
+          <a-select v-model:value="historyParams.interval" style="width: 200px">
+            <a-select-option v-for="[key, value] in Array.from(intervalMap)" :key="key" :value="key">
+              {{ value }}
+            </a-select-option>
+          </a-select>
+        </a-form-item>
+        <a-form-item label="开始时间">
+          <a-date-picker
+            v-model:value="historyParams.startTime"
+            style="width: 200px"
+            show-time
+            valueFormat="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择开始时间"
+          />
+        </a-form-item>
+        <a-form-item label="结束时间">
+          <a-date-picker
+            v-model:value="historyParams.endTime"
+            style="width: 200px"
+            show-time
+            valueFormat="YYYY-MM-DD HH:mm:ss"
+            placeholder="请选择结束时间"
+          />
+        </a-form-item>
+        <a-form-item>
+          <a-button type="primary" html-type="submit">查询</a-button>
+        </a-form-item>
+      </a-form>
+    </div>
+    <Pagination
+      v-model:current="pagination.current"
+      v-model:pageSize="pagination.pageSize"
+      :total="pagination.total"
+      size="small"
+      @change="handlePageChange"
+      style="position: absolute; z-index: 99; top: 53px; right: 30px"
+    />
+    <div class="history-chart">
+      <BarAndLine
+        :charts-columns="chartsColumns"
+        chartsType="history"
+        :option="{
+          legend: {
+            top: '5',
+          },
+          grid: {
+            top: 50,
+            left: 100,
+            right: 100,
+            bottom: 50,
+          },
+        }"
+        :data-source="dataSource"
+        height="290px"
+        :x-axis-prop-type="stationType !== 'redis' ? 'ttime' : 'time'"
+      />
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+//ts语法
+import { watchEffect, ref, watch, nextTick, reactive, onMounted, computed } from 'vue';
+import { FormSchema } from '/@/components/Form/index';
+import { defHttp } from '/@/utils/http/axios';
+import { Pagination } from 'ant-design-vue';
+import dayjs from 'dayjs';
+import BarAndLine from '/@/components/chart/BarAndLine.vue';
+import { getDictItemsByCode } from '/@/utils/dict';
+import { get } from 'lodash-es';
+
+const props = defineProps({
+  columnsType: {
+    type: String,
+  },
+  columns: {
+    type: Array,
+    // required: true,
+    default: () => [],
+  },
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceListApi: {
+    type: Function,
+  },
+  deviceArr: {
+    type: Array,
+    // required: true,
+    default: () => [],
+  },
+  designScope: {
+    type: String,
+  },
+  sysId: {
+    type: String,
+  },
+  deviceId: {
+    type: String,
+  },
+  scroll: {
+    type: Object,
+    default: { y: 0 },
+  },
+  formSchemas: {
+    type: Array<FormSchema>,
+    default: () => [],
+  },
+  /** 仅展示已绑定设备,选择是则从系统中获取sysId下已绑定设备。仅能查询到已绑定设备的历史数据 */
+  onlyBounedDevices: {
+    type: Boolean,
+    default: false,
+  },
+  showHistoryCurve: {
+    type: Boolean,
+    default: false,
+  },
+});
+const getDeviceListApi = (params) => defHttp.post({ url: '/monitor/device', params });
+const historyTable = ref();
+const loading = ref(false);
+const stationType = ref('plc1');
+const dataSource = ref([]);
+const intervalMap = new Map([
+  ['1', '1秒'],
+  ['2', '5秒'],
+  ['3', '10秒'],
+  ['4', '30秒'],
+  ['5', '1分钟'],
+  ['6', '10分钟'],
+  ['7', '30分钟'],
+  ['8', '1小时'],
+  ['9', '1天'],
+]);
+const historyParams = reactive({
+  startTime: dayjs().startOf('date').format('YYYY-MM-DD HH:mm:ss').toString(),
+  endTime: dayjs().format('YYYY-MM-DD HH:mm:ss').toString(),
+  skip: '8',
+  interval: '1小时',
+  selectedDeviceId: '',
+});
+const emit = defineEmits(['change']);
+
+const historyType = ref('');
+const deviceKide = ref('');
+let deviceOptions = ref([]);
+const deviceTypeStr = ref('');
+const deviceTypeName = ref('');
+const deviceType = ref('');
+const chartsColumns = ref([
+  // {
+  //   legend: '压差',
+  //   seriesName: '(Pa)',
+  //   ymax: 100,
+  //   yname: 'Pa',
+  //   linetype: 'bar',
+  //   yaxispos: 'left',
+  //   color: '#37BCF2',
+  //   sort: 1,
+  //   xRotate: 0,
+  //   dataIndex: 'frontRearDP',
+  // },
+  {
+    legend: '前门推力',
+    seriesName: '',
+    ymax: 100,
+    yname: '前门推力',
+    linetype: 'line',
+    yaxispos: 'left',
+    color: '#37BCF2',
+    sort: 1,
+    xRotate: 0,
+    dataIndex: '1zdqfktl',
+  },
+  {
+    legend: '后门推力',
+    seriesName: '-',
+    ymax: 100,
+    yname: '后门推力',
+    linetype: 'line',
+    yaxispos: 'right',
+    color: '#FC4327',
+    sort: 2,
+    xRotate: 0,
+    dataIndex: '2zdqfktl',
+  },
+]);
+loading.value = true;
+const pagination = {
+  current: 1,
+  pageSize: 20,
+  showQuickJumper: false,
+  total: 0,
+};
+const selectedOption = computed<Record<string, any> | undefined>(() => {
+  let idval: string | undefined = getForm()?.getFieldsValue()?.gdeviceids;
+  if (VENT_PARAM.historyIsMultiple && idval) {
+    const arr = idval.split(',');
+    idval = arr[arr.length - 1];
+  }
+  return deviceOptions.value.find((e: any) => {
+    return e.value === idval;
+  });
+});
+
+watch(
+  () => {
+    return props.columnsType;
+  },
+  async (newVal) => {
+    if (!newVal) return;
+    deviceKide.value = newVal;
+    if (historyTable.value) {
+      getForm().resetFields();
+      // getForm().updateSchema();
+      // getForm();
+    }
+    dataSource.value = [];
+    // const column = getTableHeaderColumns(newVal.includes('_history') ? newVal : newVal + '_history');
+    // if (column && column.length < 1) {
+    //   const arr = newVal.split('_');
+    //   console.log('历史记录列表表头------------>', arr[0] + '_monitor');
+    //   columns.value = getTableHeaderColumns(arr[0] + '_history');
+    //   if (columns.value.length < 1) {
+    //     if (historyType.value) {
+    //       columns.value = getTableHeaderColumns(historyType.value + '_history');
+    //     }
+    //   }
+    // } else {
+    //   columns.value = column;
+    // }
+    await getDeviceList();
+    nextTick(() => {
+      getDataSource();
+    });
+
+    if (historyTable.value) reload();
+  },
+  {
+    immediate: true,
+  }
+);
+
+watch(historyType, (type) => {
+  if (!type) return;
+  // if (historyTable.value) getForm().resetFields()
+
+  // const column = getTableHeaderColumns(type.includes('_history') ? type : type + '_history');
+  // if (column && column.length < 1) {
+  //   const arr = type.split('_');
+  //   columns.value = getTableHeaderColumns(arr[0] + '_history');
+  // } else {
+  //   columns.value = column;
+  // }
+  // setColumns(columns.value);
+});
+
+const showCurve = ref(false);
+
+// 是否显示历史曲线,在devices_shows_history_curve字典里可以配置哪些设备类型需要显示曲线
+// 字典内的字段可以是前缀,例如fanlocal之于fanlocal_normal
+// 安全监控设备需要更多的配置,除去配置safetymonitor,还需要配置哪些安全监控设备需要曲线
+// 因此可以配置例如A1001的dataTypeName代码(可以查看真实数据参考)
+function calcShowCurveValue() {
+  const historyCurveDicts = getDictItemsByCode('devices_shows_history_curve') || [];
+  const findDict = (str) => historyCurveDicts.some(({ value }) => str.startsWith(value));
+
+  if (!props.showHistoryCurve) return false;
+  const dt = props.deviceType; // 依赖项
+
+  if (!findDict(dt)) return false;
+  if (!dt.startsWith('safetymonitor')) return true;
+
+  // 和字典的设备类型匹配后,如果是安全监控设备,需要额外的匹配安全监控类型
+  const dtns = get(selectedOption.value, 'readData.dataTypeName', ''); // 依赖项
+  return findDict(dtns);
+}
+
+// const tableScroll = computed(() => {
+//   if (props.scroll.y && showCurve.value) return { y: props.scroll.y - 450 };
+//   if (props.scroll.y) return { y: props.scroll.y - 100 };
+//   return {};
+// });
+
+watch(
+  () => props.deviceId,
+  async () => {
+    // await getForm().setFieldsValue({});
+    await getDeviceList();
+  }
+);
+
+/** 获取可供查询历史数据的设备列表 */
+async function getDeviceList() {
+  // if (props.deviceType.split('_')[1] && props.deviceType.split('_')[1] === 'history') return;
+  let result;
+  let response;
+  if (props.onlyBounedDevices) {
+    response = await getDeviceListApi({
+      systemID: props.sysId,
+      devicetype: 'sys',
+    }).then(({ msgTxt }) => {
+      return { msgTxt: msgTxt.filter((e) => e.type === props.deviceType) };
+    });
+  } else if (props.sysId) {
+    response = await getDeviceListApi({
+      sysId: props.sysId,
+      devicetype: props.deviceType.startsWith('vehicle') ? 'location_normal' : props.deviceType,
+      pageSize: 10000,
+    });
+  } else if (props.deviceListApi) {
+    response = await props.deviceListApi();
+  } else {
+    response = await getDeviceListApi({ devicetype: props.deviceType, pageSize: 10000 });
+  }
+
+  // 处理不同格式的数据
+  if (response['records'] && response['records'].length > 0) {
+    result = response['records'];
+  } else if (response['msgTxt'] && response['msgTxt'][0] && response['msgTxt'][0]['datalist']) {
+    result = response['msgTxt'][0]['datalist'];
+  }
+  if (response['msgTxt'] && response['msgTxt'][0]) {
+    deviceTypeName.value = response['msgTxt'][0]['typeName'];
+    deviceType.value = response['msgTxt'][0]['type'];
+  }
+
+  if (result) {
+    deviceOptions.value = [];
+    deviceOptions.value = result.map((item, index) => {
+      return {
+        label: item['strinstallpos'],
+        value: item['id'] || item['deviceID'],
+        strtype: item['strtype'] || item['deviceType'],
+        strinstallpos: item['strinstallpos'],
+        devicekind: item['devicekind'],
+        stationtype: item['stationtype'],
+        readData: item['readData'],
+      };
+    });
+
+    stationType.value = deviceOptions.value[0]['stationtype'];
+    if (props.deviceType.startsWith('vehicle')) {
+      historyType.value = 'vehicle';
+    } else {
+      historyType.value = deviceOptions.value[0]['strtype'] || deviceOptions.value[0]['devicekind'];
+    }
+
+    /** 此处使用nextTick是由于可能表单暂未更新,而下面的方法依赖表单项 */
+    nextTick(() => {
+      showCurve.value = calcShowCurveValue();
+      // initHistoryCurveColumns();
+    });
+  }
+  if (VENT_PARAM.historyIsMultiple) {
+    // await getForm().setFieldsValue({
+    //   gdeviceids: [props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : ''],
+    // });
+    // await getForm().updateSchema({
+    //   field: 'gdeviceids',
+    //   componentProps: {
+    //     mode: 'multiple',
+    //     maxTagCount: 'responsive',
+    //   },
+    // });
+  } else {
+    // await getForm().setFieldsValue({
+    //   gdeviceids: props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : '',
+    // });
+    // await getForm().updateSchema({
+    //   field: 'gdeviceids',
+    // });
+  }
+}
+function handlePageChange(page, size) {
+  console.log('当前页:', page, '每页条数:', size);
+  // 此处发起数据请求
+  pagination.current = page;
+  pagination.pageSize = size;
+  getDataSource();
+}
+function resetFormParam() {
+  const formData = {};
+  formData['pageNo'] = pagination.current;
+  formData['pageSize'] = pagination.pageSize;
+  formData['ttime_begin'] = historyParams.startTime;
+  formData['ttime_end'] = historyParams.endTime;
+  formData['column'] = 'createTime';
+  formData['gdeviceids'] = props.deviceId ? props.deviceId : deviceOptions.value[0] ? deviceOptions.value[0]['value'] : '';
+
+  if (stationType.value !== 'redis' && deviceOptions.value[0]) {
+    formData['strtype'] = deviceTypeStr.value
+      ? deviceTypeStr.value
+      : deviceOptions.value[0]['strtype']
+      ? deviceOptions.value[0]['strtype']
+      : props.deviceType + '*';
+    if (props.sysId) {
+      formData['sysId'] = props.sysId;
+    }
+    return formData;
+  } else {
+    const params = {
+      pageNum: pagination['current'],
+      pageSize: pagination['pageSize'],
+      column: pagination['createTime'],
+      startTime: formData['ttime_begin'],
+      endTime: formData['ttime_end'],
+      deviceId: formData['gdeviceids'],
+      strtype: props.deviceType + '*',
+      sysId: props.sysId,
+      interval: intervalMap.get(formData['skip']) ? intervalMap.get(formData['skip']) : '1h',
+      isEmployee: props.deviceType.startsWith('vehicle') ? false : true,
+    };
+    return params;
+  }
+}
+
+async function getDataSource() {
+  dataSource.value = [];
+  const params = await resetFormParam();
+  if (stationType.value !== 'redis') {
+    const result = await defHttp.get({ url: '/safety/ventanalyMonitorData/listdays', params: params });
+    pagination.total = Math.abs(result['datalist']['total']) || 0;
+    if (result['datalist']['records'].length > 0) {
+      dataSource.value = result['datalist']['records'].map((item: any) => {
+        return Object.assign(item, item['readData']);
+      });
+    } else {
+      dataSource.value = [];
+    }
+  } else {
+    const result = await defHttp.post({ url: '/monitor/history/getHistoryData', params: params });
+    pagination.total = Math.abs(result['total']) || 0;
+    dataSource.value = result['records'] || [];
+  }
+}
+
+watchEffect(() => {
+  if (historyTable.value && dataSource) {
+    const data = dataSource.value || [];
+    emit('change', data);
+  }
+});
+
+onMounted(async () => {
+  await getDeviceList();
+  console.log(deviceOptions.value, 'abacaca');
+  if (deviceOptions.value[0]) {
+    nextTick(async () => {
+      await getDataSource();
+    });
+  }
+});
+</script>
+
+<style scoped lang="less">
+@import '/@/design/theme.less';
+
+:deep(.@{ventSpace}-table-body) {
+  height: auto !important;
+}
+:deep(.zxm-picker) {
+  height: 30px !important;
+}
+.history-table {
+  width: 100%;
+  :deep(.jeecg-basic-table-form-container) {
+    .@{ventSpace}-form {
+      padding: 0 !important;
+      border: none !important;
+      margin-bottom: 0 !important;
+      .@{ventSpace}-picker,
+      .@{ventSpace}-select-selector {
+        width: 100% !important;
+        height: 100%;
+        background: #00000017;
+        border: 1px solid #b7b7b7;
+        input,
+        .@{ventSpace}-select-selection-item,
+        .@{ventSpace}-picker-suffix {
+          color: #fff;
+        }
+        .@{ventSpace}-select-selection-placeholder {
+          color: #ffffffaa;
+        }
+      }
+    }
+    .@{ventSpace}-table-title {
+      min-height: 0 !important;
+    }
+  }
+  .pagination-box {
+    display: flex;
+    justify-content: flex-end;
+    align-items: center;
+    .page-num {
+      border: 1px solid #0090d8;
+      padding: 4px 8px;
+      margin-right: 5px;
+      color: #0090d8;
+    }
+    .btn {
+      margin-right: 10px;
+    }
+  }
+}
+
+.history-chart {
+  background-color: #0090d822;
+  margin: 0 10px;
+}
+
+.charts-container {
+  --image-no-camera_bg: url('/@/assets/images/vent/no-data.png');
+  position: relative;
+  height: 100%;
+  .form-container {
+    display: flex;
+    // justify-content: center;
+    margin-top: 10px !important;
+    margin-bottom: 10px !important;
+  }
+  .charts-box {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    bottom: 0;
+    top: 0px;
+  }
+
+  .@{ventSpace}-picker,
+  .@{ventSpace}-select-selector {
+    background: #00000017 !important;
+    border: 1px solid @vent-form-item-border !important;
+    input,
+    .@{ventSpace}-select-selection-item,
+    .@{ventSpace}-picker-suffix {
+      color: #fff !important;
+    }
+    .@{ventSpace}-select-selection-placeholder {
+      color: #b7b7b7 !important;
+    }
+  }
+  .@{ventSpace}-select-arrow,
+  .@{ventSpace}-picker-separator {
+    color: #fff !important;
+  }
+}
+
+.no-data {
+  width: 100%;
+  height: 475px;
+  padding-top: 80px;
+  background: var(--image-no-camera_bg) no-repeat;
+  background-position: center;
+  display: flex;
+  justify-content: center;
+  font-size: 50px;
+  color: var(--vent-text-base);
+}
+:deep(.@{ventSpace}-select-dropdown) {
+  color: #000 !important;
+  .@{ventSpace}-select-item {
+    color: #000 !important;
+  }
+}
+.zxm-form-inline .zxm-form-item > .zxm-form-item-label > label {
+  color: #fff !important;
+}
+.page-info {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 17 - 5
src/views/vent/monitorManager/gateMonitor/gate.data.ts

@@ -290,15 +290,27 @@ export const chartsColumns = [
     dataIndex: 'frontRearDP',
   },
   // {
-  //   legend: '气源压力',
-  //   seriesName: '(MPa)',
-  //   ymax: 50,
-  //   yname: 'MPa',
+  //   legend: '前门推力',
+  //   seriesName: '',
+  //   ymax: 100,
+  //   yname: '前门推力',
+  //   linetype: 'line',
+  //   yaxispos: 'left',
+  //   color: '#37BCF2',
+  //   sort: 1,
+  //   xRotate: 0,
+  //   dataIndex: '1zdqfktl',
+  // },
+  // {
+  //   legend: '后门推力',
+  //   seriesName: '-',
+  //   ymax: 100,
+  //   yname: '后门推力',
   //   linetype: 'line',
   //   yaxispos: 'right',
   //   color: '#FC4327',
   //   sort: 2,
   //   xRotate: 0,
-  //   dataIndex: 'sourcePressure',
+  //   dataIndex: '2zdqfktl',
   // },
 ];

+ 776 - 737
src/views/vent/monitorManager/gateMonitor/index.vue

@@ -290,6 +290,30 @@
               />
             </div>
           </a-tab-pane>
+          <!-- v-if="sysOrgCode === 'sdmtjtswmk'" -->
+          <a-tab-pane v-if="sysOrgCode === 'sdmtjtswmk'" key="2" tab="风门轴反馈推力曲线">
+            <div class="tab-item" v-if="activeKey === '2'">
+              <!-- <div class="history-chart">
+                <BarAndLine
+                  :charts-columns="chartsColumns"
+                  chartsType="history"
+                  :option="Option"
+                  :data-source="sharedData"
+                  height="290px"
+                  :x-axis-prop-type="stationType !== 'redis' ? 'ttime' : 'time'"
+                />
+              </div> -->
+              <HistoryTableChart
+                chartsColumnsType="gate_chart"
+                :dataSource="sharedData"
+                height="100%"
+                :chartsColumns="chartsColumns"
+                device-type="gate"
+                :is-show-child-type="true"
+              >
+              </HistoryTableChart>
+            </div>
+          </a-tab-pane>
         </a-tabs>
       </dv-border-box8>
     </div>
@@ -317,823 +341,838 @@
 </template>
 
 <script setup lang="ts">
-  import { onBeforeUnmount, onUnmounted, onMounted, ref, reactive, nextTick, inject, unref } from 'vue';
-  import MonitorTable from '../comment/MonitorTable.vue';
-  import HistoryTable from '../comment/HistoryTable.vue';
-  import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
-  import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
-  import AlarmHistoryTableHj from './components/AlarmHistoryTableHj.vue';
-  import HandleModal from './modal.vue';
-  import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
-  import { mountedThree, addMonitorText, play, destroy, setModelType, computePlay } from './gate.threejs';
-  import { deviceControlApi } from '/@/api/vent/index';
-  import { message } from 'ant-design-vue';
-  import { list, getTableList, cameraList, cameraAddrList } from './gate.api';
-  import lodash from 'lodash';
-  import { setDivHeight } from '/@/utils/event';
-  import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
-  import { useRouter } from 'vue-router';
-  import LivePlayer from '@liveqing/liveplayer-v3';
-  import { useModal } from '/@/components/Modal';
-  import { useCamera } from '/@/hooks/system/useCamera';
-  import { usePermission } from '/@/hooks/web/usePermission';
-  import { getDictItems } from '/@/api/common/api';
-  import { render } from '/@/utils/common/renderUtils';
-  import { useGlobSetting } from '/@/hooks/setting';
-  import { getDictItemsByCode } from '/@/utils/dict';
+import { onBeforeUnmount, onUnmounted, onMounted, ref, reactive, nextTick, inject, unref } from 'vue';
+import MonitorTable from '../comment/MonitorTable.vue';
+import HistoryTable from '../comment/HistoryTable.vue';
+import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
+import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
+import AlarmHistoryTableHj from './components/AlarmHistoryTableHj.vue';
+import HandleModal from './modal.vue';
+import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
+import { mountedThree, addMonitorText, play, destroy, setModelType, computePlay } from './gate.threejs';
+import { deviceControlApi } from '/@/api/vent/index';
+import { message } from 'ant-design-vue';
+import { list, getTableList, cameraList, cameraAddrList } from './gate.api';
+import { chartsColumns } from './gate.data';
+import lodash from 'lodash';
+import { setDivHeight } from '/@/utils/event';
+import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
+import { useRouter } from 'vue-router';
+import LivePlayer from '@liveqing/liveplayer-v3';
+import { useModal } from '/@/components/Modal';
+import { useCamera } from '/@/hooks/system/useCamera';
+import { usePermission } from '/@/hooks/web/usePermission';
+import { getDictItems } from '/@/api/common/api';
+import { render } from '/@/utils/common/renderUtils';
+import { useGlobSetting } from '/@/hooks/setting';
+import { getDictItemsByCode } from '/@/utils/dict';
+import { defHttp } from '/@/utils/http/axios';
+import BarAndLine from '/@/components/chart/BarAndLine.vue';
+import HistoryTableChart from '../comment/HistoryTableChart.vue';
+const { hasPermission } = usePermission();
+const { sysOrgCode } = useGlobSetting();
+const globalConfig = inject('globalConfig');
 
-  const { hasPermission } = usePermission();
-  const { sysOrgCode } = useGlobSetting();
-  const globalConfig = inject('globalConfig');
-
-  const { currentRoute } = useRouter();
-  const MonitorDataTable = ref();
-  let contrlValue = '';
-  const playerRef = ref();
-  const deviceType = ref('gate');
-  const activeKey = ref('1'); // tab
-  const loading = ref(false);
-
-  const scroll = reactive({
-    y: 230,
-  });
-  const modelList = ref<{ text: string; value: string }[]>([]);
-  const frontDoorIsOpen = ref(false); //前门是否开启
-  const backDoorIsOpen = ref(false); //后门是否开启
-  const midDoorIsOpen = ref(false); //中间门是否开启
+const { currentRoute } = useRouter();
+const MonitorDataTable = ref();
+let contrlValue = '';
+const playerRef = ref();
+const deviceType = ref('gate');
+const activeKey = ref('1'); // tab
+const loading = ref(false);
+const stationType = ref('plc1');
+const scroll = reactive({
+  y: 230,
+});
+const modelList = ref<{ text: string; value: string }[]>([]);
+const frontDoorIsOpen = ref(false); //前门是否开启
+const backDoorIsOpen = ref(false); //后门是否开启
+const midDoorIsOpen = ref(false); //中间门是否开启
 
-  const modalIsShow = ref<boolean>(false); // 是否显示模态框
-  const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
-  const modalType = ref(''); // 模态框内容显示类型,设备操作类型
+const modalIsShow = ref<boolean>(false); // 是否显示模态框
+const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
+const modalType = ref(''); // 模态框内容显示类型,设备操作类型
 
-  const selectRowIndex = ref(-1); // 选中行
-  const dataSource = ref([]);
+const selectRowIndex = ref(-1); // 选中行
+const dataSource = ref([]);
+const sharedData = ref([]);
+const deviceBaseList = ref([]); // 设备基本信息
+const updateSharedData = (data) => {
+  sharedData.value = data;
+};
+const Option = {
+  grid: {
+    top: '20%',
+    left: '5%',
+    right: '5%',
+    bottom: '3%',
+    containLabel: true,
+  },
+  toolbox: {
+    feature: null,
+  },
+};
+const [registerModal, { openModal, closeModal }] = useModal();
 
-  const deviceBaseList = ref([]); // 设备基本信息
-  const [registerModal, { openModal, closeModal }] = useModal();
+const { getCamera, removeCamera } = useCamera();
 
-  const { getCamera, removeCamera } = useCamera();
+const tabChange = (activeKeyVal) => {
+  activeKey.value = activeKeyVal;
+  if (activeKeyVal == 1) {
+    nextTick(() => {
+      if (MonitorDataTable.value) MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
+    });
+  }
+};
 
-  const tabChange = (activeKeyVal) => {
-    activeKey.value = activeKeyVal;
-    if (activeKeyVal == 1) {
-      nextTick(() => {
-        if (MonitorDataTable.value) MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
-      });
-    }
-  };
+const initData = {
+  deviceID: '',
+  deviceType: '',
+  strname: '',
+  frontRearDP: '-', //压差
+  // sourcePressure: '-', //气源压力
+  runRoRecondition: null,
+  autoRoManual: null,
+  netStatus: '0', //通信状态
+  frontGateOpen: '0',
+  frontGateClose: '1',
+  rearGateOpen: '0',
+  rearGateClose: '1',
+  midGateOpen: '0',
+  midGateClose: '1',
+  fault: '气源压力超限',
+  masterComputer: 0,
+  frontGateOpenCtrl: false,
+  rearGateOpenCtrl: false,
+  cameras: [],
+};
 
-  const initData = {
-    deviceID: '',
-    deviceType: '',
-    strname: '',
-    frontRearDP: '-', //压差
-    // sourcePressure: '-', //气源压力
-    runRoRecondition: null,
-    autoRoManual: null,
-    netStatus: '0', //通信状态
-    frontGateOpen: '0',
-    frontGateClose: '1',
-    rearGateOpen: '0',
-    rearGateClose: '1',
-    midGateOpen: '0',
-    midGateClose: '1',
-    fault: '气源压力超限',
-    masterComputer: 0,
-    frontGateOpenCtrl: false,
-    rearGateOpenCtrl: false,
-    cameras: [],
-  };
+// 监测数据
+const selectData = reactive(lodash.cloneDeep(initData));
 
-  // 监测数据
-  const selectData = reactive(lodash.cloneDeep(initData));
+const flvURL1 = () => {
+  // return ''
+  return `/video/gate.mp4`;
+};
 
-  const flvURL1 = () => {
-    // return ''
-    return `/video/gate.mp4`;
-  };
-
-  function deviceEdit(e: Event, type: string, record) {
-    e.stopPropagation();
-    openModal(true, {
-      type,
-      deviceId: record['deviceID'],
-    });
-  }
-  // 获取设备基本信息列表
-  function getDeviceBaseList() {
-    getTableList({ pageSize: 1000 }).then((res) => {
-      deviceBaseList.value = res.records;
-    });
-  }
+function deviceEdit(e: Event, type: string, record) {
+  e.stopPropagation();
+  openModal(true, {
+    type,
+    deviceId: record['deviceID'],
+  });
+}
+// 获取设备基本信息列表
+function getDeviceBaseList() {
+  getTableList({ pageSize: 1000 }).then((res) => {
+    deviceBaseList.value = res.records;
+  });
+}
 
-  // https获取监测数据
-  let timer: null | NodeJS.Timeout = null;
-  async function getMonitor(flag?) {
-    if (Object.prototype.toString.call(timer) === '[object Null]') {
-      timer = await setTimeout(
-        async () => {
-          const res = await list({ devicetype: deviceType.value, pagetype: 'normal' });
-          if (res.msgTxt && res.msgTxt[0]) {
-            dataSource.value = res.msgTxt[0].datalist || [];
-            dataSource.value.forEach((data: any) => {
-              const readData = data.readData;
-              data = Object.assign(data, readData);
-            });
-            if (dataSource.value.length > 0 && selectRowIndex.value == -1 && MonitorDataTable.value) {
-              // 初始打开页面
-              if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
-                MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
-              } else {
-                MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
-              }
-            }
-            Object.assign(selectData, dataSource.value[selectRowIndex.value]);
-            if (selectData.contrlMod == 'jnjhCtrl') {
-              selectData['autoRoManual'] = selectData['autoRoManual'] == 1 ? true : false;
-              selectData['autoRoManual1'] = selectData['autoRoManual1'] == 1 ? true : false;
-              selectData['autoRoManual2'] = selectData['autoRoManual2'] == 1 ? true : false;
-            }
-            addMonitorText(selectData);
-            monitorAnimation(selectData);
-            if (timer) {
-              timer = null;
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+async function getMonitor(flag?) {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = await setTimeout(
+      async () => {
+        const res = await list({ devicetype: deviceType.value, pagetype: 'normal' });
+        if (res.msgTxt && res.msgTxt[0]) {
+          dataSource.value = res.msgTxt[0].datalist || [];
+          dataSource.value.forEach((data: any) => {
+            const readData = data.readData;
+            data = Object.assign(data, readData);
+          });
+          if (dataSource.value.length > 0 && selectRowIndex.value == -1 && MonitorDataTable.value) {
+            // 初始打开页面
+            if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
+              MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
+            } else {
+              MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
             }
-            getMonitor();
           }
-        },
-        flag ? 0 : 1000
-      );
-    }
+          Object.assign(selectData, dataSource.value[selectRowIndex.value]);
+          if (selectData.contrlMod == 'jnjhCtrl') {
+            selectData['autoRoManual'] = selectData['autoRoManual'] == 1 ? true : false;
+            selectData['autoRoManual1'] = selectData['autoRoManual1'] == 1 ? true : false;
+            selectData['autoRoManual2'] = selectData['autoRoManual2'] == 1 ? true : false;
+          }
+          addMonitorText(selectData);
+          monitorAnimation(selectData);
+          if (timer) {
+            timer = null;
+          }
+          getMonitor();
+        }
+      },
+      flag ? 0 : 1000
+    );
   }
+}
 
-  // 切换检测数据
-  async function getSelectRow(selectRow, index) {
-    if (!selectRow) return;
-    loading.value = true;
-    selectRowIndex.value = index;
+// 切换检测数据
+async function getSelectRow(selectRow, index) {
+  if (!selectRow) return;
+  loading.value = true;
+  selectRowIndex.value = index;
 
-    const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
-    Object.assign(selectData, initData, selectRow, baseData);
-    isFrontOpenRunning = false; //开关门动作是否在进行
-    isRearOpenRunning = false; //开关门动作是否在进行
-    isMidOpenRunning = false; //开关门动作是否在进行
-    frontDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
-    rearDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
-    midDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+  const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
+  Object.assign(selectData, initData, selectRow, baseData);
+  isFrontOpenRunning = false; //开关门动作是否在进行
+  isRearOpenRunning = false; //开关门动作是否在进行
+  isMidOpenRunning = false; //开关门动作是否在进行
+  frontDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+  rearDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+  midDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
 
-    let type;
-    const dictCodes = getDictItemsByCode('gateStyle');
-    if (selectData && dictCodes && dictCodes.length > 0) {
-      const gateStyle = selectData['gateStyle'];
-      switch (gateStyle) {
-        case 'gate_qd':
-          type = 'fm3';
-          break;
-        case 'fmtl3':
-          type = 'fmThreeTl';
-          break;
-        case 'fmSs':
-          type = 'fmTwoSs';
-          break;
-        case 'fm_fc':
-          type = 'fmWindow';
-          break;
-        case 'fmXr':
-          type = 'fmXr';
-          break;
-        case 'fmYy':
-          type = 'fm1';
-          break;
-        case 'fmSs3':
-          type = 'fm2';
-          break;
-        case 'fm_fc_hjg':
-          type = 'fmWindowHjg';
-          break;
-        case 'fm_fc_zhq':
-          type = 'fmWindowZhq';
-          break;
-      }
-    } else {
-      type = selectData.nwindownum == 1 ? 'singleWindow' : 'doubleWindow';
-      if (selectData['doorUse'] == 2) {
-        type = 'fmXr';
-      } else if (selectData.ndoorcount == '3' || selectData.deviceType == 'gate_nomal3') {
+  let type;
+  const dictCodes = getDictItemsByCode('gateStyle');
+  if (selectData && dictCodes && dictCodes.length > 0) {
+    const gateStyle = selectData['gateStyle'];
+    switch (gateStyle) {
+      case 'gate_qd':
+        type = 'fm3';
+        break;
+      case 'fmtl3':
         type = 'fmThreeTl';
-      } else {
-        if (selectData.deviceType == 'gate_ss') {
-          type = 'fm2';
-          // type = 'fmWindow';
-        } else if (selectData.deviceType == 'gate_qd' || selectData.deviceType == 'gate_normal') {
-          type = 'fm3';
-        } else if (selectData.deviceType == 'gate_ss_two' || selectData.deviceType == 'gate_ss_two1') {
-          type = 'fmTwoSs';
-        } else if (selectData.deviceType == 'gate_tj') {
-          type = 'fmWindow';
-        } else {
-          type = 'fm1'; // 液压
-        }
-      }
-    }
-    debugger;
-    setModelType(type).then(async () => {
-      addMonitorText(selectData);
-      loading.value = false;
-    });
-    await getCamera(selectRow.deviceID, playerRef.value);
-  }
-
-  // 播放动画
-  function playAnimation(handlerState, data: any = null) {
-    const value = data;
-    switch (handlerState) {
-      case 1: // 打开前门
-        if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1') {
-          modalTitle.value = '打开前门';
-          modalType.value = '1';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('前门已经打开或正在打开,请勿重新操作');
-          message.warning('没有监测到前门关到位,无法进行指令下发操作');
-        }
         break;
-      case 2: // 关闭前门
-        if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0') {
-          modalTitle.value = '关闭前门';
-          modalType.value = '2';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('前门已经关闭或正在关闭,请勿重新操作');
-          message.warning('没有监测到前门开到位,无法进行指令下发操作');
-        }
+      case 'fmSs':
+        type = 'fmTwoSs';
         break;
-      case 3: // 打开后门
-        if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
-          modalTitle.value = '打开后门';
-          modalType.value = '3';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('后门已经打开或正在打开,请勿重新操作');
-          message.warning('没有监测到后门关到位,无法进行指令下发操作');
-        }
+      case 'fm_fc':
+        type = 'fmWindow';
         break;
-      case 4: // 关闭后门
-        if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
-          modalTitle.value = '关闭后门';
-          modalType.value = '4';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('后门已经关闭或正在关闭,请勿重新操作');
-          message.warning('没有监测到后门开到位,无法进行指令下发操作');
-        }
+      case 'fmXr':
+        type = 'fmXr';
         break;
-      case 8: // 打开中间门
-        if (selectData.midGateOpen == '0' && selectData.midGateClose == '1') {
-          modalTitle.value = '打开中间门';
-          modalType.value = '8';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('后门已经打开或正在打开,请勿重新操作');
-          message.warning('没有监测到中间门关到位,无法进行指令下发操作');
-        }
+      case 'fmYy':
+        type = 'fm1';
         break;
-      case 9: // 关闭中间门
-        if (selectData.midGateOpen == '1' && selectData.midGateClose == '0') {
-          modalTitle.value = '关闭中间门';
-          modalType.value = '9';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('后门已经关闭或正在关闭,请勿重新操作');
-          message.warning('没有监测到中间门开到位,无法进行指令下发操作');
-        }
+      case 'fmSs3':
+        type = 'fm2';
         break;
-      case 5: // 打开前后门
-        if (
-          selectData.frontGateOpen == '0' &&
-          selectData.frontGateClose == '1' &&
-          selectData.rearGateOpen == '0' &&
-          selectData.rearGateClose == '1'
-        ) {
-          modalTitle.value = '打开前后门';
-          modalType.value = '5';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('前后门已经打开或正在打开,请勿重新操作');
-          message.warning('没有监测到前门、后门关到位,无法进行指令下发操作');
-        }
+      case 'fm_fc_hjg':
+        type = 'fmWindowHjg';
         break;
-      case 6: // 关闭前后门
-        if (
-          selectData.frontGateOpen == '1' &&
-          selectData.frontGateClose == '0' &&
-          selectData.rearGateOpen == '1' &&
-          selectData.rearGateClose == '0'
-        ) {
-          modalTitle.value = '关闭前后门';
-          modalType.value = '6';
-          modalIsShow.value = true;
-        } else {
-          // message.warning('前后门已经关闭或正在关闭,请勿重新操作');
-          message.warning('没有监测到前门、后门开到位,无法进行指令下发操作');
-        }
+      case 'fm_fc_zhq':
+        type = 'fmWindowZhq';
         break;
+    }
+  } else {
+    type = selectData.nwindownum == 1 ? 'singleWindow' : 'doubleWindow';
+    if (selectData['doorUse'] == 2) {
+      type = 'fmXr';
+    } else if (selectData.ndoorcount == '3' || selectData.deviceType == 'gate_nomal3') {
+      type = 'fmThreeTl';
+    } else {
+      if (selectData.deviceType == 'gate_ss') {
+        type = 'fm2';
+        // type = 'fmWindow';
+      } else if (selectData.deviceType == 'gate_qd' || selectData.deviceType == 'gate_normal') {
+        type = 'fm3';
+      } else if (selectData.deviceType == 'gate_ss_two' || selectData.deviceType == 'gate_ss_two1') {
+        type = 'fmTwoSs';
+      } else if (selectData.deviceType == 'gate_tj') {
+        type = 'fmWindow';
+      } else {
+        type = 'fm1'; // 液压
+      }
+    }
+  }
+  debugger;
+  setModelType(type).then(async () => {
+    addMonitorText(selectData);
+    loading.value = false;
+  });
+  await getCamera(selectRow.deviceID, playerRef.value);
+}
 
-      case 7: // 控制模式切换
-        modalTitle.value = '控制模式切换';
-        modalType.value = '7';
+// 播放动画
+function playAnimation(handlerState, data: any = null) {
+  const value = data;
+  switch (handlerState) {
+    case 1: // 打开前门
+      if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1') {
+        modalTitle.value = '打开前门';
+        modalType.value = '1';
         modalIsShow.value = true;
-        break;
-
-      case 10: // 风窗控制
-        modalTitle.value = 'A窗控制';
-        modalType.value = '10';
+      } else {
+        // message.warning('前门已经打开或正在打开,请勿重新操作');
+        message.warning('没有监测到前门关到位,无法进行指令下发操作');
+      }
+      break;
+    case 2: // 关闭前门
+      if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0') {
+        modalTitle.value = '关闭前门';
+        modalType.value = '2';
         modalIsShow.value = true;
-        break;
-
-      case 11: // 风窗控制
-        modalTitle.value = 'B窗控制';
-        modalType.value = '11';
+      } else {
+        // message.warning('前门已经关闭或正在关闭,请勿重新操作');
+        message.warning('没有监测到前门开到位,无法进行指令下发操作');
+      }
+      break;
+    case 3: // 打开后门
+      if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
+        modalTitle.value = '打开后门';
+        modalType.value = '3';
         modalIsShow.value = true;
-        break;
-      case 12: // 风窗控制
-        modalTitle.value = 'C窗控制';
-        modalType.value = '12';
+      } else {
+        // message.warning('后门已经打开或正在打开,请勿重新操作');
+        message.warning('没有监测到后门关到位,无法进行指令下发操作');
+      }
+      break;
+    case 4: // 关闭后门
+      if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
+        modalTitle.value = '关闭后门';
+        modalType.value = '4';
         modalIsShow.value = true;
-        break;
-      case 13: // 风窗控制
-        modalTitle.value = 'D窗控制';
-        modalType.value = '13';
+      } else {
+        // message.warning('后门已经关闭或正在关闭,请勿重新操作');
+        message.warning('没有监测到后门开到位,无法进行指令下发操作');
+      }
+      break;
+    case 8: // 打开中间门
+      if (selectData.midGateOpen == '0' && selectData.midGateClose == '1') {
+        modalTitle.value = '打开中间门';
+        modalType.value = '8';
         modalIsShow.value = true;
-        break;
-    }
+      } else {
+        // message.warning('后门已经打开或正在打开,请勿重新操作');
+        message.warning('没有监测到中间门关到位,无法进行指令下发操作');
+      }
+      break;
+    case 9: // 关闭中间门
+      if (selectData.midGateOpen == '1' && selectData.midGateClose == '0') {
+        modalTitle.value = '关闭中间门';
+        modalType.value = '9';
+        modalIsShow.value = true;
+      } else {
+        // message.warning('后门已经关闭或正在关闭,请勿重新操作');
+        message.warning('没有监测到中间门开到位,无法进行指令下发操作');
+      }
+      break;
+    case 5: // 打开前后门
+      if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1' && selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
+        modalTitle.value = '打开前后门';
+        modalType.value = '5';
+        modalIsShow.value = true;
+      } else {
+        // message.warning('前后门已经打开或正在打开,请勿重新操作');
+        message.warning('没有监测到前门、后门关到位,无法进行指令下发操作');
+      }
+      break;
+    case 6: // 关闭前后门
+      if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0' && selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
+        modalTitle.value = '关闭前后门';
+        modalType.value = '6';
+        modalIsShow.value = true;
+      } else {
+        // message.warning('前后门已经关闭或正在关闭,请勿重新操作');
+        message.warning('没有监测到前门、后门开到位,无法进行指令下发操作');
+      }
+      break;
 
-    if (globalConfig?.simulatedPassword) {
-      handleOK('', handlerState + '');
-    }
-    contrlValue = value;
+    case 7: // 控制模式切换
+      modalTitle.value = '控制模式切换';
+      modalType.value = '7';
+      modalIsShow.value = true;
+      break;
+
+    case 10: // 风窗控制
+      modalTitle.value = 'A窗控制';
+      modalType.value = '10';
+      modalIsShow.value = true;
+      break;
+
+    case 11: // 风窗控制
+      modalTitle.value = 'B窗控制';
+      modalType.value = '11';
+      modalIsShow.value = true;
+      break;
+    case 12: // 风窗控制
+      modalTitle.value = 'C窗控制';
+      modalType.value = '12';
+      modalIsShow.value = true;
+      break;
+    case 13: // 风窗控制
+      modalTitle.value = 'D窗控制';
+      modalType.value = '13';
+      modalIsShow.value = true;
+      break;
   }
-  // 保德缺打开状态
 
-  // function playAnimation(handlerState, data: any = null) {
-  //   const value = data;
-  //   switch (handlerState) {
-  //     case 1: // 打开前门
-  //       modalTitle.value = '打开前门';
-  //       modalType.value = '1';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 2: // 关闭前门
-  //       modalTitle.value = '关闭前门';
-  //       modalType.value = '2';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 3: // 打开后门
-  //       modalTitle.value = '打开后门';
-  //       modalType.value = '3';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 4: // 关闭后门
-  //       modalTitle.value = '关闭后门';
-  //       modalType.value = '4';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 8: // 打开中间门
-  //       modalTitle.value = '打开中间门';
-  //       modalType.value = '8';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 9: // 关闭中间门
-  //       modalTitle.value = '关闭中间门';
-  //       modalType.value = '9';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 5: // 打开前后门
-  //       modalTitle.value = '打开前后门';
-  //       modalType.value = '5';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 6: // 关闭前后门
-  //       modalTitle.value = '关闭前后门';
-  //       modalType.value = '6';
-  //       modalIsShow.value = true;
-  //       break;
+  if (globalConfig?.simulatedPassword) {
+    handleOK('', handlerState + '');
+  }
+  contrlValue = value;
+}
+// 保德缺打开状态
 
-  //     case 7: // 控制模式切换
-  //       modalTitle.value = '控制模式切换';
-  //       modalType.value = '7';
-  //       modalIsShow.value = true;
-  //       break;
-  //     case 10: // 风窗控制
-  //       modalTitle.value = '风窗控制';
-  //       modalType.value = '10';
-  //       modalIsShow.value = true;
-  //       break;
-  //   }
+// function playAnimation(handlerState, data: any = null) {
+//   const value = data;
+//   switch (handlerState) {
+//     case 1: // 打开前门
+//       modalTitle.value = '打开前门';
+//       modalType.value = '1';
+//       modalIsShow.value = true;
+//       break;
+//     case 2: // 关闭前门
+//       modalTitle.value = '关闭前门';
+//       modalType.value = '2';
+//       modalIsShow.value = true;
+//       break;
+//     case 3: // 打开后门
+//       modalTitle.value = '打开后门';
+//       modalType.value = '3';
+//       modalIsShow.value = true;
+//       break;
+//     case 4: // 关闭后门
+//       modalTitle.value = '关闭后门';
+//       modalType.value = '4';
+//       modalIsShow.value = true;
+//       break;
+//     case 8: // 打开中间门
+//       modalTitle.value = '打开中间门';
+//       modalType.value = '8';
+//       modalIsShow.value = true;
+//       break;
+//     case 9: // 关闭中间门
+//       modalTitle.value = '关闭中间门';
+//       modalType.value = '9';
+//       modalIsShow.value = true;
+//       break;
+//     case 5: // 打开前后门
+//       modalTitle.value = '打开前后门';
+//       modalType.value = '5';
+//       modalIsShow.value = true;
+//       break;
+//     case 6: // 关闭前后门
+//       modalTitle.value = '关闭前后门';
+//       modalType.value = '6';
+//       modalIsShow.value = true;
+//       break;
 
-  //   if (globalConfig?.simulatedPassword) {
-  //     handleOK('', handlerState + '');
-  //   }
-  //   contrlValue = value;
-  // }
+//     case 7: // 控制模式切换
+//       modalTitle.value = '控制模式切换';
+//       modalType.value = '7';
+//       modalIsShow.value = true;
+//       break;
+//     case 10: // 风窗控制
+//       modalTitle.value = '风窗控制';
+//       modalType.value = '10';
+//       modalIsShow.value = true;
+//       break;
+//   }
 
-  function handleOK(passWord, handlerState, value?) {
-    if (!passWord && !globalConfig?.simulatedPassword) {
-      message.warning('请输入密码');
-      return;
-    }
-    if (isOpenRunning) {
-      message.warning('风门正在运行。。。');
-      modalIsShow.value = false;
-      return;
-    }
-    const data = {
-      deviceid: selectData.deviceID,
-      devicetype: selectData.deviceType,
-      paramcode: '',
-      value: contrlValue,
-      password: passWord || globalConfig?.simulatedPassword,
-      masterComputer: selectData.masterComputer,
-    };
-    let handler = () => {};
-    debugger;
+//   if (globalConfig?.simulatedPassword) {
+//     handleOK('', handlerState + '');
+//   }
+//   contrlValue = value;
+// }
 
-    switch (handlerState) {
-      case '1': // 打开前门
-        if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1') {
-          handler = () => {
-            frontDoorIsOpen.value = true;
-          };
-          data.paramcode = 'frontGateOpen_S';
-        } else {
-          message.warning('前门已打开。。。');
-          modalIsShow.value = false;
-        }
-        break;
-      case '2': // 关闭前门
-        if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0') {
-          handler = () => {
-            frontDoorIsOpen.value = false;
-          };
-          data.paramcode = 'frontGateClose_S';
-        } else {
-          message.warning('前门已关闭。。。');
-          modalIsShow.value = false;
-        }
-        break;
-      case '3': // 打开后门
-        if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
-          handler = () => {
-            backDoorIsOpen.value = true;
-          };
-          data.paramcode = 'rearGateOpen_S';
-        } else {
-          message.warning('后门已打开。。。');
-          modalIsShow.value = false;
-        }
-        break;
-      case '4': // 关闭后门
-        if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
-          handler = () => {
-            backDoorIsOpen.value = false;
-          };
-          data.paramcode = 'rearGateClose_S';
-        } else {
-          message.warning('后门已关闭。。。');
-          modalIsShow.value = false;
-        }
-        break;
-      case '8': // 打开中间门
-        if (selectData.midGateOpen == '0' && selectData.midGateClose == '1') {
-          handler = () => {
-            midDoorIsOpen.value = true;
-          };
-          data.paramcode = 'midGateOpen_S';
-        } else {
-          message.warning('中间风门已打开。。。');
-          modalIsShow.value = false;
-        }
-        break;
-      case '9': // 关闭中间门
-        if (selectData.midGateOpen == '1' && selectData.midGateClose == '0') {
-          handler = () => {
-            midDoorIsOpen.value = false;
-          };
-          data.paramcode = 'midGateClose_S';
-        } else {
-          message.warning('中间风门已关闭。。。');
-          modalIsShow.value = false;
-        }
-        break;
-      case '5': // 打开前后门
-        if (
-          selectData.frontGateOpen == '0' &&
-          selectData.frontGateClose == '1' &&
-          selectData.rearGateOpen == '0' &&
-          selectData.rearGateClose == '1'
-        ) {
-          handler = () => {
-            frontDoorIsOpen.value = true;
-            backDoorIsOpen.value = true;
-          };
-          data.paramcode = 'sameTimeOpen';
-        }
-        break;
-      case '6': // 关闭前后门
-        if (
-          selectData.frontGateOpen == '1' &&
-          selectData.frontGateClose == '0' &&
-          selectData.rearGateOpen == '1' &&
-          selectData.rearGateClose == '0'
-        ) {
-          handler = () => {
-            frontDoorIsOpen.value = false;
-            backDoorIsOpen.value = false;
-          };
-          data.paramcode = 'sameTimeClose';
-        }
-        break;
-      case '7': // 远程与就地
-        if (selectData.contrlMod == 'codeCtrl') {
-          if (contrlValue == '1') {
-            data.paramcode = 'autoRoManualControl1';
-          } else if (contrlValue == '0') {
-            data.paramcode = 'autoRoManualControl2';
-          } else {
-            data.paramcode = 'autoRoManualControl0';
-          }
-          data.value = '';
-          selectData.autoRoManual = null;
-        } else if (selectData.contrlMod == 'loopCtrl' || selectData.contrlMod == 'jnjhCtrl') {
-          data.paramcode = 'autoRoManualControl';
-          data.value = '';
-          selectData.autoRoManual = null;
+function handleOK(passWord, handlerState, value?) {
+  if (!passWord && !globalConfig?.simulatedPassword) {
+    message.warning('请输入密码');
+    return;
+  }
+  if (isOpenRunning) {
+    message.warning('风门正在运行。。。');
+    modalIsShow.value = false;
+    return;
+  }
+  const data = {
+    deviceid: selectData.deviceID,
+    devicetype: selectData.deviceType,
+    paramcode: '',
+    value: contrlValue,
+    password: passWord || globalConfig?.simulatedPassword,
+    masterComputer: selectData.masterComputer,
+  };
+  let handler = () => {};
+  debugger;
+
+  switch (handlerState) {
+    case '1': // 打开前门
+      if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1') {
+        handler = () => {
+          frontDoorIsOpen.value = true;
+        };
+        data.paramcode = 'frontGateOpen_S';
+      } else {
+        message.warning('前门已打开。。。');
+        modalIsShow.value = false;
+      }
+      break;
+    case '2': // 关闭前门
+      if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0') {
+        handler = () => {
+          frontDoorIsOpen.value = false;
+        };
+        data.paramcode = 'frontGateClose_S';
+      } else {
+        message.warning('前门已关闭。。。');
+        modalIsShow.value = false;
+      }
+      break;
+    case '3': // 打开后门
+      if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
+        handler = () => {
+          backDoorIsOpen.value = true;
+        };
+        data.paramcode = 'rearGateOpen_S';
+      } else {
+        message.warning('后门已打开。。。');
+        modalIsShow.value = false;
+      }
+      break;
+    case '4': // 关闭后门
+      if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
+        handler = () => {
+          backDoorIsOpen.value = false;
+        };
+        data.paramcode = 'rearGateClose_S';
+      } else {
+        message.warning('后门已关闭。。。');
+        modalIsShow.value = false;
+      }
+      break;
+    case '8': // 打开中间门
+      if (selectData.midGateOpen == '0' && selectData.midGateClose == '1') {
+        handler = () => {
+          midDoorIsOpen.value = true;
+        };
+        data.paramcode = 'midGateOpen_S';
+      } else {
+        message.warning('中间风门已打开。。。');
+        modalIsShow.value = false;
+      }
+      break;
+    case '9': // 关闭中间门
+      if (selectData.midGateOpen == '1' && selectData.midGateClose == '0') {
+        handler = () => {
+          midDoorIsOpen.value = false;
+        };
+        data.paramcode = 'midGateClose_S';
+      } else {
+        message.warning('中间风门已关闭。。。');
+        modalIsShow.value = false;
+      }
+      break;
+    case '5': // 打开前后门
+      if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1' && selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
+        handler = () => {
+          frontDoorIsOpen.value = true;
+          backDoorIsOpen.value = true;
+        };
+        data.paramcode = 'sameTimeOpen';
+      }
+      break;
+    case '6': // 关闭前后门
+      if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0' && selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
+        handler = () => {
+          frontDoorIsOpen.value = false;
+          backDoorIsOpen.value = false;
+        };
+        data.paramcode = 'sameTimeClose';
+      }
+      break;
+    case '7': // 远程与就地
+      if (selectData.contrlMod == 'codeCtrl') {
+        if (contrlValue == '1') {
+          data.paramcode = 'autoRoManualControl1';
+        } else if (contrlValue == '0') {
+          data.paramcode = 'autoRoManualControl2';
         } else {
-          data.paramcode = 'autoRoManualControl';
-          data.value = contrlValue;
-          selectData.autoRoManual = null;
+          data.paramcode = 'autoRoManualControl0';
         }
-        break;
-      case '10': // 前(A)窗控制
-        data.paramcode = 'frontSetValue1';
-        data.value = value;
-        break;
-      case '11': // 后(B)窗控制
-        data.paramcode = 'frontSetValue2';
-        data.value = value;
-        break;
-      case '12': // 后(B)窗控制
-        data.paramcode = 'rearSetValue1';
-        data.value = value;
-        break;
-      case '13': // 后(B)窗控制
-        data.paramcode = 'rearSetValue2';
-        data.value = value;
-        break;
-    }
+        data.value = '';
+        selectData.autoRoManual = null;
+      } else if (selectData.contrlMod == 'loopCtrl' || selectData.contrlMod == 'jnjhCtrl') {
+        data.paramcode = 'autoRoManualControl';
+        data.value = '';
+        selectData.autoRoManual = null;
+      } else {
+        data.paramcode = 'autoRoManualControl';
+        data.value = contrlValue;
+        selectData.autoRoManual = null;
+      }
+      break;
+    case '10': // 前(A)窗控制
+      data.paramcode = 'frontSetValue1';
+      data.value = value;
+      break;
+    case '11': // 后(B)窗控制
+      data.paramcode = 'frontSetValue2';
+      data.value = value;
+      break;
+    case '12': // 后(B)窗控制
+      data.paramcode = 'rearSetValue1';
+      data.value = value;
+      break;
+    case '13': // 后(B)窗控制
+      data.paramcode = 'rearSetValue2';
+      data.value = value;
+      break;
+  }
 
-    if (data.paramcode) {
-      deviceControlApi(data).then((res) => {
-        // 模拟时开启
-        if (res.success) {
-          modalIsShow.value = false;
-          if (globalConfig.History_Type == 'remote') {
-            message.success('指令已下发至生产管控平台成功!');
-          } else {
-            message.success('指令已下发成功!');
-          }
+  if (data.paramcode) {
+    deviceControlApi(data).then((res) => {
+      // 模拟时开启
+      if (res.success) {
+        modalIsShow.value = false;
+        if (globalConfig.History_Type == 'remote') {
+          message.success('指令已下发至生产管控平台成功!');
         } else {
-          message.error(res.message);
+          message.success('指令已下发成功!');
         }
-      });
-    }
+      } else {
+        message.error(res.message);
+      }
+    });
   }
-  let isOpenRunning = false; //开关门动作是否在进行
-  /** 开关门动画调用 */
-  let isFrontOpenRunning = false; //开关门动作是否在进行
-  // let isFrontCloseRunning = false; //开关门动作是否在进行
-  let isRearOpenRunning = false; //开关门动作是否在进行
-  // let isRearCloseRunning = false; //开关门动作是否在进行
-  let isMidOpenRunning = false; //中间门动作是否在进行
-  // let isMidCloseRunning = false; //中间门动作是否在进行
-  // 0 关闭 1 正在打开 2 打开 3正在关闭
-  let frontDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
-  let rearDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
-  let midDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
-  function monitorAnimation(selectData) {
-    const timeScale = 0.005;
-    // 带风窗 风窗动画
-    if (selectData['gateStyle'] && selectData['gateStyle'].includes('fm_fc')) playWindowAnimation(selectData);
+}
+let isOpenRunning = false; //开关门动作是否在进行
+/** 开关门动画调用 */
+let isFrontOpenRunning = false; //开关门动作是否在进行
+// let isFrontCloseRunning = false; //开关门动作是否在进行
+let isRearOpenRunning = false; //开关门动作是否在进行
+// let isRearCloseRunning = false; //开关门动作是否在进行
+let isMidOpenRunning = false; //中间门动作是否在进行
+// let isMidCloseRunning = false; //中间门动作是否在进行
+// 0 关闭 1 正在打开 2 打开 3正在关闭
+let frontDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+let rearDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+let midDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+function monitorAnimation(selectData) {
+  const timeScale = 0.005;
+  // 带风窗 风窗动画
+  if (selectData['gateStyle'] && selectData['gateStyle'].includes('fm_fc')) playWindowAnimation(selectData);
 
-    if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0' && !isFrontOpenRunning) {
-      isFrontOpenRunning = true;
-      if (frontDeviceState != 1) {
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
-        play(1, timeScale);
-        frontDeviceState = 1;
-        frontDoorIsOpen.value = false;
-        backDoorIsOpen.value = true;
-      }
+  if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0' && !isFrontOpenRunning) {
+    isFrontOpenRunning = true;
+    if (frontDeviceState != 1) {
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
+      play(1, timeScale);
+      frontDeviceState = 1;
+      frontDoorIsOpen.value = false;
+      backDoorIsOpen.value = true;
     }
+  }
 
-    if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '0' && !isFrontOpenRunning) {
-      isFrontOpenRunning = true;
-      if (frontDeviceState != 1) {
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
-        play(1, timeScale);
-        frontDeviceState = 1;
-        frontDoorIsOpen.value = false;
-        backDoorIsOpen.value = true;
-      }
+  if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '0' && !isFrontOpenRunning) {
+    isFrontOpenRunning = true;
+    if (frontDeviceState != 1) {
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
+      play(1, timeScale);
+      frontDeviceState = 1;
+      frontDoorIsOpen.value = false;
+      backDoorIsOpen.value = true;
     }
+  }
 
-    if (selectData.frontGateClose == '1' && selectData.frontGateOpen == '0' && isFrontOpenRunning) {
-      isFrontOpenRunning = false;
-      if (frontDeviceState != 0) {
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(2, timeScale) : play(2);
-        play(2, timeScale);
-        frontDeviceState = 0;
-        frontDoorIsOpen.value = false;
-        // backDoorIsOpen.value = false
-      }
+  if (selectData.frontGateClose == '1' && selectData.frontGateOpen == '0' && isFrontOpenRunning) {
+    isFrontOpenRunning = false;
+    if (frontDeviceState != 0) {
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(2, timeScale) : play(2);
+      play(2, timeScale);
+      frontDeviceState = 0;
+      frontDoorIsOpen.value = false;
+      // backDoorIsOpen.value = false
     }
-    if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0' && !isRearOpenRunning) {
-      isRearOpenRunning = true;
+  }
+  if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0' && !isRearOpenRunning) {
+    isRearOpenRunning = true;
 
-      if (rearDeviceState != 1) {
-        rearDeviceState = 1;
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
-        play(3, timeScale);
-        backDoorIsOpen.value = false;
-        frontDoorIsOpen.value = true;
-      }
+    if (rearDeviceState != 1) {
+      rearDeviceState = 1;
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
+      play(3, timeScale);
+      backDoorIsOpen.value = false;
+      frontDoorIsOpen.value = true;
     }
-    if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '0' && !isRearOpenRunning) {
-      isRearOpenRunning = true;
+  }
+  if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '0' && !isRearOpenRunning) {
+    isRearOpenRunning = true;
 
-      if (rearDeviceState != 1) {
-        rearDeviceState = 1;
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
-        play(3, timeScale);
-        backDoorIsOpen.value = false;
-        frontDoorIsOpen.value = true;
-      }
+    if (rearDeviceState != 1) {
+      rearDeviceState = 1;
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
+      play(3, timeScale);
+      backDoorIsOpen.value = false;
+      frontDoorIsOpen.value = true;
     }
+  }
 
-    if (selectData.rearGateClose == '1' && selectData.rearGateOpen == '0' && isRearOpenRunning) {
-      isRearOpenRunning = false;
-      if (rearDeviceState != 0) {
-        rearDeviceState = 0;
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(4, timeScale) : play(4);
-        play(4, timeScale);
-        backDoorIsOpen.value = false;
-      }
+  if (selectData.rearGateClose == '1' && selectData.rearGateOpen == '0' && isRearOpenRunning) {
+    isRearOpenRunning = false;
+    if (rearDeviceState != 0) {
+      rearDeviceState = 0;
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(4, timeScale) : play(4);
+      play(4, timeScale);
+      backDoorIsOpen.value = false;
     }
+  }
 
-    if (selectData.midGateOpen == '1' && selectData.midGateClose == '0' && !isMidOpenRunning) {
-      isMidOpenRunning = true;
+  if (selectData.midGateOpen == '1' && selectData.midGateClose == '0' && !isMidOpenRunning) {
+    isMidOpenRunning = true;
 
-      if (midDeviceState != 1) {
-        midDeviceState = 1;
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
-        play(8, timeScale);
-        backDoorIsOpen.value = false;
-        frontDoorIsOpen.value = true;
-      }
+    if (midDeviceState != 1) {
+      midDeviceState = 1;
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
+      play(8, timeScale);
+      backDoorIsOpen.value = false;
+      frontDoorIsOpen.value = true;
     }
+  }
 
-    if (selectData.midGateOpen == '0' && selectData.midGateClose == '0' && !isMidOpenRunning) {
-      isMidOpenRunning = true;
+  if (selectData.midGateOpen == '0' && selectData.midGateClose == '0' && !isMidOpenRunning) {
+    isMidOpenRunning = true;
 
-      if (midDeviceState != 1) {
-        midDeviceState = 1;
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
-        play(8, timeScale);
-        backDoorIsOpen.value = false;
-        frontDoorIsOpen.value = true;
-      }
+    if (midDeviceState != 1) {
+      midDeviceState = 1;
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(3, timeScale) : play(3);
+      play(8, timeScale);
+      backDoorIsOpen.value = false;
+      frontDoorIsOpen.value = true;
     }
+  }
 
-    if (selectData.midGateClose == '1' && selectData.midGateOpen == '0' && isMidOpenRunning) {
-      isMidOpenRunning = false;
-      if (midDeviceState != 0) {
-        midDeviceState = 0;
-        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(4, timeScale) : play(4);
-        play(9, timeScale);
-        backDoorIsOpen.value = false;
-      }
+  if (selectData.midGateClose == '1' && selectData.midGateOpen == '0' && isMidOpenRunning) {
+    isMidOpenRunning = false;
+    if (midDeviceState != 0) {
+      midDeviceState = 0;
+      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(4, timeScale) : play(4);
+      play(9, timeScale);
+      backDoorIsOpen.value = false;
     }
   }
+}
 
-  function playWindowAnimation(data, maxarea = 90, isFirst = false) {
-    computePlay(data, maxarea, isFirst);
-  }
+function playWindowAnimation(data, maxarea = 90, isFirst = false) {
+  computePlay(data, maxarea, isFirst);
+}
 
-  function handleCancel() {
-    modalIsShow.value = false;
-    modalTitle.value = '';
-    modalType.value = '';
-  }
+function handleCancel() {
+  modalIsShow.value = false;
+  modalTitle.value = '';
+  modalType.value = '';
+}
 
-  // // 远程、就地切换
-  // function changeType() {
-  //   const data = {
-  //     deviceid: selectData.deviceID,
-  //     devicetype: selectData.deviceType,
-  //     paramcode: 'autoRoManualControl',
-  //     value: selectData.autoRoManual,
-  //   };
-  //   deviceControlApi(data).then(() => {
-  //     if (globalConfig.History_Type == 'remote') {
-  //       message.success('指令已下发至生产管控平台成功!');
-  //     } else {
-  //       message.success('指令已下发成功!');
-  //     }
-  //   });
-  // }
+// // 远程、就地切换
+// function changeType() {
+//   const data = {
+//     deviceid: selectData.deviceID,
+//     devicetype: selectData.deviceType,
+//     paramcode: 'autoRoManualControl',
+//     value: selectData.autoRoManual,
+//   };
+//   deviceControlApi(data).then(() => {
+//     if (globalConfig.History_Type == 'remote') {
+//       message.success('指令已下发至生产管控平台成功!');
+//     } else {
+//       message.success('指令已下发成功!');
+//     }
+//   });
+// }
 
-  onMounted(async () => {
-    const { query } = unref(currentRoute);
-    if (query['deviceType']) deviceType.value = query['deviceType'] as string;
-    modelList.value = await getDictItems('gateModel');
-    loading.value = true;
-    const playerDom = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
-    debugger;
-    mountedThree(playerDom)
-      .then(async () => {
-        if (sysOrgCode != 'zmhjhzmy') {
-          await getMonitor(true);
+// async function getDataSource() {
+//   dataSource.value = [];
+//   const params = await resetFormParam();
+//   if (stationType.value !== 'redis') {
+//     const result = await defHttp.get({ url: '/safety/ventanalyMonitorData/listdays', params: params });
+//     if (result['datalist']['records'].length > 0) {
+//       dataSource.value = result['datalist']['records'].map((item: any) => {
+//         return Object.assign(item, item['readData']);
+//       });
+//     } else {
+//       dataSource.value = [];
+//     }
+//   } else {
+//     const result = await defHttp.post({ url: '/monitor/history/getHistoryData', params: params });
+//     dataSource.value = result['records'] || [];
+//   }
+// }
+onMounted(async () => {
+  const { query } = unref(currentRoute);
+  if (query['deviceType']) deviceType.value = query['deviceType'] as string;
+  modelList.value = await getDictItems('gateModel');
+  loading.value = true;
+  const playerDom = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
+  debugger;
+  mountedThree(playerDom)
+    .then(async () => {
+      if (sysOrgCode != 'zmhjhzmy') {
+        await getMonitor(true);
+        loading.value = false;
+      } else {
+        // 韩咀无风门设备,只有报警历史数据,无其他数据
+        setModelType('fm1').then(async () => {
           loading.value = false;
-        } else {
-          // 韩咀无风门设备,只有报警历史数据,无其他数据
-          setModelType('fm1').then(async () => {
-            loading.value = false;
-            dataSource.value = [];
-            addMonitorText(selectData);
-          });
-        }
-      })
-      .catch(() => {
-        debugger;
-      });
-  });
+          dataSource.value = [];
+          addMonitorText(selectData);
+        });
+      }
+    })
+    .catch(() => {
+      debugger;
+    });
+});
 
-  onBeforeUnmount(() => {
-    getDeviceBaseList();
-  });
+onBeforeUnmount(() => {
+  getDeviceBaseList();
+});
 
-  onUnmounted(() => {
-    removeCamera();
-    if (timer) {
-      clearTimeout(timer);
-      timer = undefined;
-    }
-    destroy();
-  });
+onUnmounted(() => {
+  removeCamera();
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+  destroy();
+});
 </script>
 ,
 <style lang="less" scoped>
-  @import '/@/design/theme.less';
-  @import '/@/design/vent/modal.less';
-  .scene-box {
-    .bottom-tabs-box {
-      height: 350px;
-    }
+@import '/@/design/theme.less';
+@import '/@/design/vent/modal.less';
+.scene-box {
+  .bottom-tabs-box {
+    height: 350px;
   }
-  .button-box {
-    border: none !important;
-    height: 34px !important;
-
-    &:hover {
-      background: var(--vent-device-manager-control-btn-hover) !important;
-    }
-
-    &::before {
-      height: 27px !important;
-      background: var(--vent-device-manager-control-btn) !important;
-    }
+}
+.button-box {
+  border: none !important;
+  height: 34px !important;
 
-    &::after {
-      top: 35px !important;
-    }
+  &:hover {
+    background: var(--vent-device-manager-control-btn-hover) !important;
   }
 
-  :deep(.@{ventSpace}-tabs-tabpane-active) {
-    height: 100%;
+  &::before {
+    height: 27px !important;
+    background: var(--vent-device-manager-control-btn) !important;
   }
 
-  ::-webkit-scrollbar-thumb {
-    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
-    background: #4288a444;
-  }
-  :deep(.zxm-radio-disabled + span) {
-    color: var(--vent-font-color) !important;
-  }
-  :deep(.zxm-radio-disabled .zxm-radio-inner::after) {
-    background-color: #127cb5 !important;
-  }
-  :deep(.@{ventSpace}-picker-datetime-panel) {
-    height: 200px !important;
-    overflow-y: auto !important;
+  &::after {
+    top: 35px !important;
   }
+}
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  height: 100%;
+}
+
+::-webkit-scrollbar-thumb {
+  -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+  background: #4288a444;
+}
+:deep(.zxm-radio-disabled + span) {
+  color: var(--vent-font-color) !important;
+}
+:deep(.zxm-radio-disabled .zxm-radio-inner::after) {
+  background-color: #127cb5 !important;
+}
+:deep(.@{ventSpace}-picker-datetime-panel) {
+  height: 200px !important;
+  overflow-y: auto !important;
+}
 </style>

+ 85 - 81
src/views/vent/monitorManager/mainFanMonitor/components/AnalysisTable.vue

@@ -1,95 +1,99 @@
 <template>
   <div class="alarm-history-table">
+<<<<<<< HEAD
     <a-table :dataSource="mockData" :columns="Warncolumns" :scroll="{ y: 300 }"> </a-table>
+=======
+    <a-table :dataSource="mockData" :columns="Warncolumns" :scroll="{ y: 180 }" />
+>>>>>>> 903e6f21078b572ce6c9a42b53bcf33197b02a1f
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref } from 'vue';
+  import { ref } from 'vue';
 
-const Warncolumns = ref([
-  {
-    title: '序号',
-    align: 'center',
-    key: 'index',
-    width: 80,
-    customRender: ({ index }) => {
-      return index + 1;
+  const Warncolumns = ref([
+    {
+      title: '序号',
+      align: 'center',
+      key: 'index',
+      width: 80,
+      customRender: ({ index }) => {
+        return index + 1;
+      },
     },
-  },
-  {
-    title: '设备名称',
-    align: 'center',
-    width: 200,
-    customRender: () => '羊马河主通风机',
-  },
-  {
-    title: '故障描述',
-    align: 'center',
-    customRender: ({ record }) => {
-      const activeFaults = record.title;
-      return activeFaults;
+    {
+      title: '设备名称',
+      align: 'center',
+      width: 200,
+      customRender: () => '羊马河主通风机',
     },
-  },
-  {
-    title: '故障原因',
-    align: 'center',
-    key: 'faultStatus',
-    customRender: ({ record }) => {
-      const activeFaults = record.faultStatus;
-      return activeFaults;
+    {
+      title: '故障描述',
+      align: 'center',
+      customRender: ({ record }) => {
+        const activeFaults = record.title;
+        return activeFaults;
+      },
     },
-  },
-  {
-    title: '解决方案',
-    align: 'center',
-    key: 'netStatus',
-    customRender: ({ record }) => {
-      const activeFaults = record.netStatus;
-      return activeFaults;
+    {
+      title: '故障原因',
+      align: 'center',
+      key: 'faultStatus',
+      customRender: ({ record }) => {
+        const activeFaults = record.faultStatus;
+        return activeFaults;
+      },
     },
-  },
-  {
-    title: '时间',
-    align: 'center',
-    key: 'readTime',
-    customRender: () => {
-      const now = new Date();
-      return now.toLocaleString(); // 格式化为本地时间字符串
+    {
+      title: '解决方案',
+      align: 'center',
+      key: 'netStatus',
+      customRender: ({ record }) => {
+        const activeFaults = record.netStatus;
+        return activeFaults;
+      },
     },
-  },
-]);
+    {
+      title: '时间',
+      align: 'center',
+      key: 'readTime',
+      customRender: () => {
+        const now = new Date();
+        return now.toLocaleString(); // 格式化为本地时间字符串
+      },
+    },
+  ]);
 
-const mockData = [
-  {
-    key: 0,
-    title: '水平或垂直振动>6mm',
-    faultStatus: '通风阻力增大;静压值低于正常运行值100pa',
-    netStatus: '检查相关参数传感器、增大风机运行频率',
-  },
-  {
-    key: 1,
-    title: '前轴/后轴温度>70℃',
-    faultStatus: '缺乏润滑脂或轴承损坏',
-    netStatus: '检查轴承润滑脂状态、检查轴承是否损坏、检查相关参数传感器',
-  },
-  {
-    key: 2,
-    title: '前轴/后轴温度>105℃',
-    faultStatus: '轴承损坏',
-    netStatus: '检查轴承是否损坏',
-  },
-  {
-    key: 3,
-    title: '水平或垂直振动>8mm,且变化范围较大',
-    faultStatus: '电机轴承发生损坏;风机扇叶发生损坏',
-    netStatus: '检查振动传感器、检查电机轴承、检查风机扇叶',
-  },
-  {
-    key: 4,
-    title: '额定电压超过额定值的10%时',
-    faultStatus: '电网电压出现出现异常或者通风阻力增大',
-    netStatus: '检查相关参数传感器、检查电网电压',
-  },
-];
-</script>
+  const mockData = [
+    {
+      key: 0,
+      title: '水平或垂直振动>6mm',
+      faultStatus: '通风阻力增大;静压值低于正常运行值100pa',
+      netStatus: '检查相关参数传感器、增大风机运行频率',
+    },
+    {
+      key: 1,
+      title: '前轴/后轴温度>70℃',
+      faultStatus: '缺乏润滑脂或轴承损坏',
+      netStatus: '检查轴承润滑脂状态、检查轴承是否损坏、检查相关参数传感器',
+    },
+    {
+      key: 2,
+      title: '前轴/后轴温度>105℃',
+      faultStatus: '轴承损坏',
+      netStatus: '检查轴承是否损坏',
+    },
+    {
+      key: 3,
+      title: '水平或垂直振动>8mm,且变化范围较大',
+      faultStatus: '电机轴承发生损坏;风机扇叶发生损坏',
+      netStatus: '检查振动传感器、检查电机轴承、检查风机扇叶',
+    },
+    {
+      key: 4,
+      title: '额定电压超过额定值的10%时',
+      faultStatus: '电网电压出现出现异常或者通风阻力增大',
+      netStatus: '检查相关参数传感器、检查电网电压',
+    },
+  ];
+</script>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 768 - 576
src/views/vent/monitorManager/mainFanMonitor/index.vue


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

@@ -1159,8 +1159,8 @@ export const initData1 = () => {
 
 // 大柳塔武当沟
 export const initData = (deviceType?) => {
-  // const { sysOrgCode } = useGlobSetting();
-  const sysOrgCode = 'sdtljtdhzmk';
+  const { sysOrgCode } = useGlobSetting();
+  // const sysOrgCode = 'sdtljtdhzmk';
   if (sysOrgCode == 'sdmtjtdltmk') {
     return initDataDlt(deviceType);
   } else if (sysOrgCode == 'sdmtjtswmk') {

+ 252 - 99
src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts

@@ -4,7 +4,9 @@ import UseThree from '../../../../utils/threejs/useThree';
 import mainWindRect from './mainWind.threejs';
 import mainXjWindRect from './mainWind.xj.threejs';
 import mainLjWindRect from './mainWind.lj.threejs';
+import mainWindLj3 from './mainWind.li3.threejs';
 import useEvent from '../../../../utils/threejs/useEvent';
+import { getDictItemsByCode } from '/@/utils/dict';
 
 // import * as dat from 'dat.gui';
 // const gui = new dat.GUI();
@@ -17,6 +19,7 @@ let model: UseThree | undefined, //
   mainWindObj: mainWindRect | undefined,
   mainXjWindObj: mainXjWindRect | undefined,
   mainLjWindObj: mainLjWindRect | undefined,
+  mainLj3WindObj: mainWindLj3 | undefined,
   modalType = 'mainWindRect',
   explosionVentClose = -1,
   explosionVentOpen = -1;
@@ -73,6 +76,8 @@ const mouseEvent = (event) => {
         mainWindObj?.mousedownModel.call(mainWindObj, intersects);
       } else if (modalType === 'mainXjWindRect' && mainXjWindObj) {
         mainXjWindObj?.mousedownModel.call(mainXjWindObj, intersects);
+      } else if (modalType === 'mainWindRect3' && mainLj3WindObj) {
+        mainLj3WindObj?.mousedownModel.call(mainLj3WindObj, intersects);
       }
     });
   }
@@ -97,6 +102,8 @@ export const addText = () => {
     return mainXjWindObj.addCssText.call(mainXjWindObj);
   } else if (modalType === 'mainLjWindRect' && mainLjWindObj) {
     return mainLjWindObj.addCssText.call(mainLjWindObj);
+  } else if (modalType === 'mainWindRect3' && mainLj3WindObj) {
+    return mainLj3WindObj.addCssText.call(mainLj3WindObj);
   }
 };
 
@@ -109,6 +116,8 @@ export const resetEcharts = (selectData) => {
     return mainXjWindObj.addEcharts.call(mainXjWindObj);
   } else if (modalType === 'mainLjWindRect' && mainLjWindObj) {
     return mainLjWindObj.addEcharts.call(mainLjWindObj);
+  } else if (modalType === 'mainWindRect3' && mainLj3WindObj) {
+    return mainLj3WindObj.addEcharts.call(mainLj3WindObj);
   }
 };
 
@@ -129,6 +138,8 @@ export const play = (controlType, deviceType, frequencyVal?, state?, smokeDirect
     return mainXjWindObj.playSmoke.call(mainXjWindObj, controlType, deviceType, frequencyVal, state, smokeDirection);
   } else if (modalType === 'mainLjWindRect' && mainLjWindObj) {
     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);
   }
 };
 
@@ -142,6 +153,8 @@ export const playAnimate1 = async (selectData, duration?) => {
     mainObj = mainXjWindObj;
   } else if (modalType === 'mainLjWindRect') {
     mainObj = mainLjWindObj;
+  } else if (modalType === 'mainWindRect3') {
+    mainObj = mainLj3WindObj;
   }
   if (selectData && mainObj) {
     if (selectData.Fan1WindowOpen !== undefined) {
@@ -224,7 +237,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 | undefined;
+  let mainObj: mainWindRect | mainXjWindRect | mainWindLj3 | undefined;
 
   if (modalType === 'mainWindRect') {
     mainObj = mainWindObj;
@@ -232,97 +245,181 @@ export const playAnimate = async (selectData, duration?) => {
     mainObj = mainXjWindObj;
   } else if (modalType === 'mainLjWindRect') {
     mainObj = mainLjWindObj;
+  } else if (modalType === 'mainWindRect3') {
+    mainObj = mainLj3WindObj;
   }
   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.Fan2FreqHz, duration);
-    mainObj.resetSmokeParam('back', selectData.Fan1FreqHz, duration);
-    if (selectData.Fan2StartStatus == 1) {
-      // 主风机开启
-      mainObj?.lookMotor('front', 'open', duration);
-      mainObj?.openOrCloseValve('front', 'open', duration);
-      // 1. 已经运行,首次切入动画
-      // 2. 在页面上,切换动画
-      if (selectData.Fan2FreqForwardRun == 1 && selectData.Fan2FreqReverseRun == 0) {
-        // 主风机正转
-        if (mainObj['airChu2'] && !mainObj['airChu2'].visible) {
-          mainObj['airJin1'].visible = false;
-          mainObj['airJin2'].visible = false;
-          mainObj['airChu1'].visible = false;
-          mainObj['airChu2'].visible = true;
-        }
-        mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
-        await mainObj.setSmokeDirection('front', 'tubPositivePath');
-      } else if (selectData.Fan2FreqReverseRun == 1 && selectData.Fan2FreqForwardRun == 0) {
-        // 主风机反转
-        if (mainObj['airJin2'] && !mainObj['airJin2'].visible) {
-          mainObj['airJin1'].visible = false;
-          mainObj['airJin2'].visible = true;
-          mainObj['airChu1'].visible = false;
-          mainObj['airChu2'].visible = false;
+    if (selectData['Fan3FreqHz'] == undefined || selectData['Fan3FreqHz'] == null || selectData['Fan3FreqHz'] == '') selectData['Fan3FreqHz'] = 50;
+    if (modalType === 'mainWindRect3') {
+      mainObj.resetSmokeParam('front', selectData.Fan1FreqHz, duration);
+      mainObj.resetSmokeParam('center', selectData.Fan2FreqHz, duration);
+      mainObj.resetSmokeParam('back', selectData.Fan3FreqHz, 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 {
+          mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
+          await mainObj.setSmokeDirection('front', 'tubPositivePath');
         }
-        mainObj.startGearAnimation('front', 'open', 'tubInversePath', selectData.Fan2FreqHz, duration);
-        await mainObj.setSmokeDirection('front', 'tubInversePath');
+
+        if (!mainObj?.frontSmoke?.frameId) mainObj?.frontSmoke?.startSmoke(duration);
       } else {
-        // 默认主风机正转
-        if (mainObj['airChu2'] && !mainObj['airChu2'].visible) {
-          mainObj['airJin1'].visible = false;
-          mainObj['airJin2'].visible = false;
-          mainObj['airChu1'].visible = false;
-          mainObj['airChu2'].visible = true;
-        }
-        mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
-        await mainObj.setSmokeDirection('front', 'tubPositivePath');
+        // 主风机停止
+        mainObj.closeDevice('front');
       }
 
-      if (!mainObj?.frontSmoke?.frameId) mainObj?.frontSmoke?.startSmoke(duration);
-    } else {
-      // 主风机停止
-      mainObj.closeDevice('front');
-    }
-    if (selectData.Fan1StartStatus == 1) {
-      // 主风机开启
-      mainObj.lookMotor('back', 'open', duration);
-      mainObj.openOrCloseValve('back', 'open', duration);
-      // 1. 已经运行,首次切入动画
-      // 2. 在页面上,切换动画
-      if (selectData.Fan1FreqForwardRun == 1 && selectData.Fan1FreqReverseRun == 0) {
-        // 主风机正转
-        // 主风机正转
-        if (mainObj['airChu1'] && !mainObj['airChu1'].visible) {
-          mainObj['airJin1'].visible = false;
-          mainObj['airJin2'].visible = false;
-          mainObj['airChu1'].visible = true;
-          mainObj['airChu2'].visible = false;
+      if (selectData.Fan2StartStatus == 1) {
+        // 主风机开启
+        mainObj?.lookMotor('center', 'open', duration);
+        mainObj?.openOrCloseValve('center', 'open', duration);
+        // 1. 已经运行,首次切入动画
+        // 2. 在页面上,切换动画
+        if (selectData.Fan2FreqForwardRun == 1 && selectData.Fan2FreqReverseRun == 0) {
+          // 主风机正转
+          mainObj.startGearAnimation('center', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('center', 'tubPositivePath');
+        } else if (selectData.Fan2FreqReverseRun == 1 && selectData.Fan2FreqForwardRun == 0) {
+          // 主风机反转
+          mainObj.startGearAnimation('center', 'open', 'tubInversePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('center', 'tubInversePath');
+        } else {
+          // 默认主风机正转
+          mainObj.startGearAnimation('center', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('center', 'tubPositivePath');
         }
-        mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
-        await mainObj.setSmokeDirection('back', 'tubPositivePath');
-      } else if (selectData.Fan1FreqReverseRun == 1 && selectData.Fan1FreqForwardRun == 0) {
-        // 主风机反转
-        if (mainObj['airJin1'] && !mainObj['airJin1'].visible) {
-          mainObj['airJin1'].visible = true;
-          mainObj['airJin2'].visible = false;
-          mainObj['airChu1'].visible = false;
-          mainObj['airChu2'].visible = false;
+
+        if (!mainObj?.centerSmoke?.frameId) mainObj?.centerSmoke?.startSmoke(duration);
+      } else {
+        // 主风机停止
+        mainObj.closeDevice('center');
+      }
+      if (selectData.Fan3StartStatus == 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 {
+          // 默认主风机正转
+          mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('back', 'tubPositivePath');
         }
-        mainObj.startGearAnimation('back', 'open', 'tubInversePath', selectData.Fan1FreqHz, duration);
-        await mainObj.setSmokeDirection('back', 'tubInversePath');
+
+        if (!mainObj?.backSmoke?.frameId) mainObj?.backSmoke?.startSmoke(duration);
       } else {
-        if (mainObj['airChu1'] && !mainObj['airChu1'].visible) {
-          mainObj['airJin1'].visible = false;
-          mainObj['airJin2'].visible = false;
-          mainObj['airChu1'].visible = true;
-          mainObj['airChu2'].visible = false;
+        // 主风机停止
+        mainObj.closeDevice('back');
+      }
+    } else {
+      mainObj.resetSmokeParam('front', selectData.Fan2FreqHz, duration);
+      mainObj.resetSmokeParam('back', selectData.Fan1FreqHz, duration);
+      if (selectData.Fan2StartStatus == 1) {
+        // 主风机开启
+        mainObj?.lookMotor('front', 'open', duration);
+        mainObj?.openOrCloseValve('front', 'open', duration);
+        // 1. 已经运行,首次切入动画
+        // 2. 在页面上,切换动画
+        if (selectData.Fan2FreqForwardRun == 1 && selectData.Fan2FreqReverseRun == 0) {
+          // 主风机正转
+          if (mainObj['airChu2'] && !mainObj['airChu2'].visible) {
+            mainObj['airJin1'].visible = false;
+            mainObj['airJin2'].visible = false;
+            mainObj['airChu1'].visible = false;
+            mainObj['airChu2'].visible = true;
+          }
+          mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('front', 'tubPositivePath');
+        } else if (selectData.Fan2FreqReverseRun == 1 && selectData.Fan2FreqForwardRun == 0) {
+          // 主风机反转
+          if (mainObj['airJin2'] && !mainObj['airJin2'].visible) {
+            mainObj['airJin1'].visible = false;
+            mainObj['airJin2'].visible = true;
+            mainObj['airChu1'].visible = false;
+            mainObj['airChu2'].visible = false;
+          }
+          mainObj.startGearAnimation('front', 'open', 'tubInversePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('front', 'tubInversePath');
+        } else {
+          // 默认主风机正转
+          if (mainObj['airChu2'] && !mainObj['airChu2'].visible) {
+            mainObj['airJin1'].visible = false;
+            mainObj['airJin2'].visible = false;
+            mainObj['airChu1'].visible = false;
+            mainObj['airChu2'].visible = true;
+          }
+          mainObj.startGearAnimation('front', 'open', 'tubPositivePath', selectData.Fan2FreqHz, duration);
+          await mainObj.setSmokeDirection('front', 'tubPositivePath');
         }
-        mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
-        await mainObj.setSmokeDirection('back', 'tubPositivePath');
+
+        if (!mainObj?.frontSmoke?.frameId) mainObj?.frontSmoke?.startSmoke(duration);
+      } else {
+        // 主风机停止
+        mainObj.closeDevice('front');
       }
+      if (selectData.Fan1StartStatus == 1) {
+        // 主风机开启
+        mainObj.lookMotor('back', 'open', duration);
+        mainObj.openOrCloseValve('back', 'open', duration);
+        // 1. 已经运行,首次切入动画
+        // 2. 在页面上,切换动画
+        if (selectData.Fan1FreqForwardRun == 1 && selectData.Fan1FreqReverseRun == 0) {
+          // 主风机正转
+          // 主风机正转
+          if (mainObj['airChu1'] && !mainObj['airChu1'].visible) {
+            mainObj['airJin1'].visible = false;
+            mainObj['airJin2'].visible = false;
+            mainObj['airChu1'].visible = true;
+            mainObj['airChu2'].visible = false;
+          }
+          mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
+          await mainObj.setSmokeDirection('back', 'tubPositivePath');
+        } else if (selectData.Fan1FreqReverseRun == 1 && selectData.Fan1FreqForwardRun == 0) {
+          // 主风机反转
+          if (mainObj['airJin1'] && !mainObj['airJin1'].visible) {
+            mainObj['airJin1'].visible = true;
+            mainObj['airJin2'].visible = false;
+            mainObj['airChu1'].visible = false;
+            mainObj['airChu2'].visible = false;
+          }
+          mainObj.startGearAnimation('back', 'open', 'tubInversePath', selectData.Fan1FreqHz, duration);
+          await mainObj.setSmokeDirection('back', 'tubInversePath');
+        } else {
+          if (mainObj['airChu1'] && !mainObj['airChu1'].visible) {
+            mainObj['airJin1'].visible = false;
+            mainObj['airJin2'].visible = false;
+            mainObj['airChu1'].visible = true;
+            mainObj['airChu2'].visible = false;
+          }
+          mainObj.startGearAnimation('back', 'open', 'tubPositivePath', selectData.Fan1FreqHz, duration);
+          await mainObj.setSmokeDirection('back', 'tubPositivePath');
+        }
 
-      if (!mainObj?.backSmoke?.frameId) mainObj?.backSmoke?.startSmoke(duration);
-    } else {
-      // 主风机停止
-      mainObj.closeDevice('back');
+        if (!mainObj?.backSmoke?.frameId) mainObj?.backSmoke?.startSmoke(duration);
+      } else {
+        // 主风机停止
+        mainObj.closeDevice('back');
+      }
     }
 
     // 防爆门动画
@@ -358,10 +455,10 @@ export const setModelType = (type) => {
     // 停止气流动画
     mainWindObj?.stopSmoke();
     mainXjWindObj?.stopSmoke();
-
+    mainLj3WindObj?.stopSmoke();
+    mainLjWindObj?.stopSmoke();
     if (group) model?.scene?.remove(group);
     if (modalType === 'mainWindRect' && mainWindObj && mainWindObj.group) {
-      mainXjWindObj?.clearCssText();
       (<UseThree>model).startAnimation = mainWindObj.render.bind(mainWindObj);
       group = mainWindObj.group;
       setTimeout(async () => {
@@ -380,7 +477,6 @@ export const setModelType = (type) => {
         if (group) model?.scene?.add(group);
       }, 300);
     } else if (modalType === 'mainXjWindRect' && mainXjWindObj && mainXjWindObj.group) {
-      mainWindObj?.clearCssText();
       (<UseThree>model).startAnimation = mainXjWindObj.render.bind(mainXjWindObj);
       group = mainXjWindObj.group;
       setTimeout(async () => {
@@ -399,7 +495,6 @@ export const setModelType = (type) => {
         if (group) model?.scene?.add(group);
       }, 300);
     } else if (modalType === 'mainLjWindRect' && mainLjWindObj && mainLjWindObj.group) {
-      mainWindObj?.clearCssText();
       (<UseThree>model).startAnimation = mainLjWindObj.render.bind(mainLjWindObj);
       group = mainLjWindObj.group;
       setTimeout(async () => {
@@ -417,6 +512,23 @@ export const setModelType = (type) => {
         );
         if (group) model?.scene?.add(group);
       }, 300);
+    } else if (modalType === 'mainWindRect3' && mainLj3WindObj && mainLj3WindObj.group) {
+      (<UseThree>model).startAnimation = mainLj3WindObj.render.bind(mainLj3WindObj);
+      group = mainLj3WindObj.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);
     }
   });
 };
@@ -436,25 +548,66 @@ export const mountedThree = (playerVal1) => {
       bgGroup = gltf[0] as THREE.Object3D;
       bgGroup.position.set(3.43, 27.13, 22.0);
       model?.scene?.add(bgGroup);
-      mainWindObj = new mainWindRect(model, playerVal1);
-      await mainWindObj.mountedThree();
-      mainXjWindObj = new mainXjWindRect(model, playerVal1);
-      await mainXjWindObj.mountedThree();
-      mainLjWindObj = new mainLjWindRect(model, playerVal1);
-      await mainLjWindObj.mountedThree();
+
+      // 这里根据字典判断
+      const dictCodes = getDictItemsByCode('mainFanType');
+      if (dictCodes && dictCodes.length > 0) {
+        for (let i = 0; i < dictCodes.length; i++) {
+          const dict = dictCodes[i];
+          switch (dict.value) {
+            case 'lijing':
+              modalType = 'mainWindRect';
+              mainWindObj = new mainWindRect(model, playerVal1);
+              await mainWindObj.mountedThree();
+              break;
+            case 'xiejing':
+              modalType = 'mainXjWindRect';
+              mainXjWindObj = new mainXjWindRect(model, playerVal1);
+              await mainXjWindObj.mountedThree();
+              break;
+            case 'lijing1':
+              modalType = 'mainLjWindRect';
+              mainLjWindObj = new mainLjWindRect(model, playerVal1);
+              await mainLjWindObj.mountedThree();
+              break;
+            case 'lijing_3':
+              modalType = 'mainWindRect3';
+              mainLj3WindObj = new mainWindLj3(model, playerVal1);
+              await mainLj3WindObj.mountedThree();
+              break;
+          }
+        }
+      } else {
+        mainWindObj = new mainWindRect(model, playerVal1);
+        await mainWindObj.mountedThree();
+      }
+
       model?.animate();
       resolve(null);
-      if (mainWindObj.airJin1) mainWindObj.airJin1.visible = false;
-      if (mainWindObj.airJin2) mainWindObj.airJin2.visible = false;
-      if (mainWindObj.airChu1) mainWindObj.airChu1.visible = false;
-      if (mainWindObj.airChu2) mainWindObj.airChu2.visible = false;
-      if (mainXjWindObj.airJin1) mainXjWindObj.airJin1.visible = false;
-      if (mainXjWindObj.airJin2) mainXjWindObj.airJin2.visible = false;
-      if (mainXjWindObj.airChu1) mainXjWindObj.airChu1.visible = false;
-      if (mainLjWindObj.airChu2) mainLjWindObj.airChu2.visible = false;
-      if (mainLjWindObj.airJin1) mainLjWindObj.airJin1.visible = false;
-      if (mainLjWindObj.airJin2) mainLjWindObj.airJin2.visible = false;
-      if (mainLjWindObj.airChu1) mainLjWindObj.airChu1.visible = false;
+      if (mainWindObj) {
+        if (mainWindObj.airJin1) mainWindObj.airJin1.visible = false;
+        if (mainWindObj.airJin2) mainWindObj.airJin2.visible = false;
+        if (mainWindObj.airChu1) mainWindObj.airChu1.visible = false;
+        if (mainWindObj.airChu2) mainWindObj.airChu2.visible = false;
+      }
+      if (mainXjWindObj) {
+        if (mainXjWindObj.airJin1) mainXjWindObj.airJin1.visible = false;
+        if (mainXjWindObj.airJin2) mainXjWindObj.airJin2.visible = false;
+        if (mainXjWindObj.airChu1) mainXjWindObj.airChu1.visible = false;
+        if (mainXjWindObj.airChu2) mainXjWindObj.airChu2.visible = false;
+      }
+      if (mainLjWindObj) {
+        if (mainLjWindObj.airChu2) mainLjWindObj.airChu2.visible = false;
+        if (mainLjWindObj.airJin1) mainLjWindObj.airJin1.visible = false;
+        if (mainLjWindObj.airJin2) mainLjWindObj.airJin2.visible = false;
+        if (mainLjWindObj.airChu1) mainLjWindObj.airChu1.visible = false;
+      }
+      if (mainLj3WindObj) {
+        if (mainLj3WindObj.airChu2) mainLj3WindObj.airChu2.visible = false;
+        if (mainLj3WindObj.airJin1) mainLj3WindObj.airJin1.visible = false;
+        if (mainLj3WindObj.airJin2) mainLj3WindObj.airJin2.visible = false;
+        if (mainLj3WindObj.airChu1) mainLj3WindObj.airChu1.visible = false;
+      }
     });
     startAnimation();
   });

+ 787 - 0
src/views/vent/monitorManager/mainFanMonitor/mainWind.li3.threejs.ts

@@ -0,0 +1,787 @@
+import * as THREE from 'three';
+import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
+import Smoke from '/@/views/vent/comment/threejs/Smoke';
+import { PathPointList, PathGeometry } from 'three.path';
+import gsap from 'gsap';
+
+class mainWindLj3 {
+  model;
+  modelName = 'main';
+  group: THREE.Group | null = null; // 主通风机场景
+  motorGroup1: THREE.Group | null = null; //电机
+  motorGroup2: THREE.Group | null = null; //电机
+  motorGroup3: THREE.Group | null = null; //电机
+  airJin1: THREE.Mesh | null = null; //风向箭头
+  airJin2: THREE.Mesh | null = null; //风向箭头
+  airChu1: THREE.Mesh | null = null; //风向箭头
+  airChu2: THREE.Mesh | null = null; //风向箭头
+  gearFront = {
+    gear1: null, //扇叶
+    gear2: null, //扇叶
+    gear1Direction: -1,
+    gear2Direction: 1,
+    gearFrameId: undefined,
+    gearRotateFactor: 0.5,
+    endGearRotateFactor: 3,
+  };
+  gearCenter = {
+    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; // 前面风流对象
+  centerSmoke: Smoke | null = null; // 前面风流对象
+  backSmoke: Smoke | null = null; // 后面风流对象
+  player1; // 视频播放器
+  playerStartClickTime1 = new Date().getTime();
+  frontWindowGroup;
+  backWindowGroup;
+  windowAngle = 0;
+  clock = new THREE.Clock();
+  material;
+  airTexture;
+  offset = 0;
+  direction = 0; // -1 代表反向,1代表正向
+  arrowMesh;
+  constructor(model, playerVal1) {
+    this.model = model;
+    this.player1 = playerVal1;
+  }
+  // 添加 cssObject
+  addCssText() {
+    if (!this.group) {
+      return;
+    }
+
+    const mainWindLj3 = this.group?.getObjectByName('mainWindLj3');
+    const fengji = mainWindLj3?.getObjectByName('FengJi_SanFengTong');
+    const fengji1 = fengji?.getObjectByName('Feng1_1');
+    const fengji2 = fengji?.getObjectByName('Feng2_1');
+    const fengji3 = fengji?.getObjectByName('Feng3_2');
+
+    // #1
+    if (!this.group.getObjectByName('monitorText1')) {
+      const worldPosition = new THREE.Vector3();
+      fengji1?.getObjectByName('Feng1_7')?.getWorldPosition(worldPosition);
+      const element = document.getElementById('inputBox') as HTMLElement;
+      if (element) {
+        const mainCSS3D = new CSS3DObject(element);
+        mainCSS3D.name = 'monitorText1';
+        mainCSS3D.scale.set(0.09, 0.09, 0.09);
+        mainCSS3D.position.set(worldPosition.x + 12, worldPosition.y - 20, worldPosition.z - 20);
+        mainCSS3D.lookAt(worldPosition.x + 12, worldPosition.y - 0, worldPosition.z + 2);
+        this.group.add(mainCSS3D);
+      }
+    }
+    debugger;
+    //#2
+    if (!this.group.getObjectByName('monitorText2')) {
+      const worldPosition = new THREE.Vector3();
+      fengji2?.getObjectByName('Feng2_44')?.getWorldPosition(worldPosition);
+      const element = document.getElementById('inputBox1') as HTMLElement;
+      if (element) {
+        const mainCSS3D = new CSS3DObject(element);
+        mainCSS3D.name = 'monitorText2';
+        mainCSS3D.scale.set(0.09, 0.09, 0.09);
+        mainCSS3D.position.set(worldPosition.x + 12, worldPosition.y - 20, worldPosition.z - 20);
+        mainCSS3D.lookAt(worldPosition.x + 12, worldPosition.y - 0, worldPosition.z + 2);
+        this.group.add(mainCSS3D);
+      }
+    }
+    // #3
+    if (!this.group.getObjectByName('monitorText3')) {
+      const worldPosition = new THREE.Vector3();
+      fengji3?.getObjectByName('Feng3_43')?.getWorldPosition(worldPosition);
+      const element = document.getElementById('inputBox2') as HTMLElement;
+      if (element) {
+        const mainCSS3D = new CSS3DObject(element);
+        mainCSS3D.name = 'monitorText3';
+        mainCSS3D.scale.set(0.09, 0.09, 0.09);
+        mainCSS3D.position.set(worldPosition.x + 12, worldPosition.y - 20, worldPosition.z - 20);
+        mainCSS3D.lookAt(worldPosition.x + 12, worldPosition.y - 0, worldPosition.z + 2);
+        this.group.add(mainCSS3D);
+      }
+    }
+  }
+
+  clearCssText() {
+    if (this.group) {
+      const mainCSS3D1 = this.group.getObjectByName('monitorText1');
+      const mainCSS3D2 = this.group.getObjectByName('monitorText2');
+      const mainCSS3D3 = this.group.getObjectByName('monitorText3');
+      if (mainCSS3D1) this.group.remove(mainCSS3D1);
+      if (mainCSS3D2) this.group.remove(mainCSS3D2);
+      if (mainCSS3D3) this.group.remove(mainCSS3D3);
+    }
+  }
+
+  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);
+      }
+    }
+  }
+
+  /* 更新动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.airTexture) {
+      this.airTexture.offset.x = this.offset;
+      this.offset -= this.clock.getDelta() * 2;
+    }
+  }
+
+  /* 点击风窗,风窗全屏 */
+  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 if (deviceType === 'center') {
+      this.centerSmoke?.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 if (deviceType === 'center') {
+      smoke = this.centerSmoke;
+    } 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;
+    } else {
+      smoke = this.centerSmoke;
+    }
+    if (smoke && smoke.frameId) {
+      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) {
+    let smoke;
+    const pathPoints: THREE.Vector3[] = [];
+    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是由大变小
+      },
+    ];
+    const getPathPoint = () => {
+      this.arrowMesh = this.group?.getObjectByName('arrow');
+      if (this.arrowMesh) return;
+      pathPoints.push(new THREE.Vector3(16.441, 1.485, 2.614), new THREE.Vector3(35.583, 1.485, 2.614));
+      const pathPointList = new PathPointList();
+      const up = new THREE.Vector3(0, 0, 1);
+      pathPointList.set(pathPoints, 0, 0, up, false);
+      const geometry = new PathGeometry(pathPoints.length, false);
+      geometry.update(pathPointList, {
+        width: 2,
+        arrow: false,
+      });
+
+      this.arrowMesh = new THREE.Mesh(geometry, this.material);
+      this.arrowMesh.name = 'arrow';
+      this.group?.add(this.arrowMesh);
+    };
+
+    if (deviceType === 'front') {
+      smoke = this.frontSmoke;
+    } else if (deviceType === 'back') {
+      smoke = this.backSmoke;
+    } else {
+      smoke = this.centerSmoke;
+    }
+    switch (smokeDirection) {
+      case 'tubPositivePath': // 风筒正
+        smoke.setPath(tubPositivePath);
+        if (this.direction !== 1) {
+          this.direction = 1;
+          this.airTexture.repeat.x = 1;
+        }
+        break;
+      case 'tubInversePath': // 风筒反
+        smoke.setPath(tubInversePath);
+        if (this.direction !== -1) {
+          this.direction = -1;
+          this.airTexture.repeat.x = -1;
+        }
+        break;
+      case 'windowPositivePath': // 风窗正
+        smoke.setPath(windowPositivePath);
+        if (this.direction !== 1) {
+          this.direction = 1;
+          this.airTexture.repeat.x = 1;
+        }
+        break;
+      case 'windowInversePath': // 风窗反
+        smoke.setPath(windowInversePath);
+        if (this.direction !== -1) {
+          this.direction = -1;
+          this.airTexture.repeat.x = -1;
+        }
+        break;
+    }
+    getPathPoint();
+    if (deviceType === 'front') {
+      if (this.arrowMesh && this.arrowMesh.position.z !== 2.31) this.arrowMesh.position.set(-6.48, 5.51, 13.25);
+    } else if (deviceType === 'center') {
+      if (this.arrowMesh && this.arrowMesh.position.z !== -12.99) this.arrowMesh.position.set(-6.48, 5.51, -0.02);
+    } else {
+      if (this.arrowMesh && this.arrowMesh.position.z !== -12.99) this.arrowMesh.position.set(-6.48, 5.51, -14.67);
+    }
+  }
+
+  /* 播放气流动画 */
+  /**
+   *
+   * @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 if (deviceType === 'center') {
+        smoke = this.centerSmoke;
+      } 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);
+    this.closeDevice('center', false);
+  }
+
+  /* 打开或关闭蝶阀 */
+  openOrCloseValve(deviceType, flag, duration = 3) {
+    const ztfjGroup = this.group?.getObjectByName('ztfj');
+    return new Promise((resolve) => {
+      let diefa;
+      if (deviceType == 'front') {
+        diefa = ztfjGroup?.getObjectByName('butterfly_valve001') as THREE.Mesh;
+      } else if (deviceType == 'center') {
+        diefa = ztfjGroup?.getObjectByName('butterfly_valve001') as THREE.Mesh;
+      } else {
+        diefa = ztfjGroup?.getObjectByName('butterfly_valve002') 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 if (deviceType === 'center') {
+      smoke = this.centerSmoke;
+    } 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 mainWindLj3 = this.group?.getObjectByName('mainWindLj3');
+      const fengji = mainWindLj3?.getObjectByName('FengJi_SanFengTong');
+      const fengji1 = fengji?.getObjectByName('Feng1_1');
+      const fengji2 = fengji?.getObjectByName('Feng2_1');
+      const fengji3 = fengji?.getObjectByName('Feng3_2');
+
+      let mesh, mesh1, mesh2, mesh3, motorGroup;
+      mesh1 = fengji1?.getObjectByName('Feng1_97'); //前
+      mesh2 = fengji2?.getObjectByName('Feng2_94'); //中
+      mesh3 = fengji3?.getObjectByName('Feng1_97'); //后
+      if (deviceType == 'front') {
+        mesh = mesh1;
+        motorGroup = this.motorGroup1;
+      } else if (deviceType == 'center') {
+        mesh = mesh2;
+        motorGroup = this.motorGroup2;
+      } else {
+        mesh = mesh3;
+        motorGroup = this.motorGroup3;
+      }
+      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) {
+    let gearObj, gearDirection;
+    if (deviceType === 'front') {
+      gearObj = this.gearFront;
+    } else if (deviceType === 'center') {
+      gearObj = this.gearCenter;
+    } 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.4, 1.8, 100);
+    }
+    if (!this.centerSmoke) {
+      this.centerSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.4, 1.8, 100);
+    }
+    if (!this.backSmoke) {
+      this.backSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.4, 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(-11.75, 4.15, 14.39);
+    }
+    if (this.centerSmoke) {
+      await this.centerSmoke.setPoints();
+      this.centerSmoke.points.name = 'centerSmoke';
+      this.group?.add(this.centerSmoke.points);
+      this.centerSmoke.points.position.set(-11.75, 4.15, -0.69);
+    }
+    if (this.backSmoke) {
+      await this.backSmoke.setPoints();
+      this.backSmoke.points.name = 'backSmoke';
+      this.group?.add(this.backSmoke.points);
+      this.backSmoke.points.position.set(-11.75, 4.15, -15.51);
+    }
+  }
+
+  /** 初始化电机 */
+  async initMotor() {
+    const mainWindLj3 = this.group?.getObjectByName('mainWindLj3');
+    const fengji = mainWindLj3?.getObjectByName('FengJi_SanFengTong');
+    // 前电机
+    this.motorGroup1 = fengji?.getObjectByName('Feng1_1');
+    this.gearFront.gear1 = this.motorGroup1?.getObjectByName('Feng1_33');
+    this.gearFront.gear2 = this.motorGroup1?.getObjectByName('Feng1_44');
+
+    // 中间电机
+    this.motorGroup2 = fengji?.getObjectByName('Feng2_1');
+    this.gearCenter.gear1 = this.motorGroup1?.getObjectByName('Feng2_10');
+    this.gearCenter.gear2 = this.motorGroup1?.getObjectByName('Feng2_29');
+
+    // 后电机
+    this.motorGroup3 = fengji?.getObjectByName('Feng3_2');
+    this.gearBack.gear1 = this.motorGroup1?.getObjectByName('Feng3_10');
+    this.gearBack.gear2 = this.motorGroup1?.getObjectByName('Feng3_28');
+  }
+
+  mountedThree() {
+    this.group = new THREE.Group();
+    return new Promise(async (resolve) => {
+      this.model.setGLTFModel(['bg1', 'mainWindLj3'], this.group).then(async () => {
+        // this.group = gltf[0];
+
+        console.log(this.group);
+        this.group?.position.set(-0.44, 19.88, 22.37);
+        const mainWindLj3 = this.group?.getObjectByName('mainWindLj3') as THREE.Group;
+        mainWindLj3.position.set(0, 1.48, 2.94);
+        mainWindLj3.scale.set(2.5, 2.5, 2.5);
+        this.initSmokeMass();
+        await this.setSmokePosition();
+
+        const ztfjGroup = mainWindLj3?.getObjectByName('FengJi_SanFengTong');
+        const fegnji = ztfjGroup?.getObjectByName('Feng1_1');
+
+        const mesh = fegnji?.getObjectByName('Feng1_97') as THREE.Mesh; //前
+        if (mesh && mesh.material) this.oldMaterial = mesh.material as THREE.MeshStandardMaterial;
+        await this.initMotor();
+        resolve(null);
+
+        const loader = new THREE.TextureLoader();
+        this.airTexture = loader.load('/model/img/air.png');
+        this.airTexture.wrapS = THREE.RepeatWrapping;
+        this.airTexture.repeat.set(1, 1.2);
+        this.airTexture.offset.y = 0;
+        this.airTexture.matrix.scale(0.5, 0.5);
+        this.airTexture.needsUpdate = true;
+        this.material = new THREE.MeshBasicMaterial({
+          map: this.airTexture,
+          transparent: true,
+          side: THREE.FrontSide,
+        });
+        this.clock.start();
+      });
+    });
+  }
+
+  destroy() {
+    if (this.frontSmoke) this.frontSmoke.clearSmoke();
+    if (this.centerSmoke) this.centerSmoke.clearSmoke();
+    if (this.backSmoke) 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.gearCenter.gear1 = undefined;
+    this.gearCenter.gear2 = undefined;
+
+    this.gearBack.gear1 = undefined;
+    this.gearBack.gear2 = undefined;
+
+    this.frontSmoke = undefined;
+    this.centerSmoke = undefined;
+    this.backSmoke = undefined;
+
+    this.model = undefined;
+    this.group = undefined;
+  }
+}
+
+export default mainWindLj3;

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov