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

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

bobo04052021@163.com пре 11 часа
родитељ
комит
0b2a54abea

+ 3 - 1
src/views/vent/deviceManager/configurationTable/types.ts

@@ -150,7 +150,7 @@ export interface CommonItem {
 
 export interface ModuleDataBoard extends ReadFrom {
   /** 展示牌预设的背景类型 */
-  type: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'New' | 'New1' | 'New2' | 'New3'| 'J' | 'K' | 'L' | 'M' | 'N' | 'O';
+  type: 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'New' | 'New1' | 'New2' | 'New3' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O';
   /** 展示牌布局,决定是 label 部分在上方或是 value 在上方 */
   layout: 'val-top' | 'label-top' | 'new-top' | 'new1-top' | 'new2-top' | 'new3-top';
   /** 核心配置,每个展示牌对应一项 */
@@ -272,6 +272,8 @@ export interface ModuleDataChart extends ReadFrom {
     /** 参考echarts格式化文本 */
     formatter?: string;
   };
+  /** 是否在数据更新后完全更新,在无法正确更新图表数据时可以启用 */
+  clear?: boolean;
 }
 
 export interface ModuleDataTable extends ReadFrom {

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

@@ -970,6 +970,6 @@
 
   function initCharts() {
     const o = genChartOption();
-    setOptions(o as EChartsOption, false);
+    setOptions(o as EChartsOption, Boolean(props.chartConfig.clear));
   }
 </script>

+ 160 - 183
src/views/vent/home/configurable/components/preset/selectorDualChart.vue

@@ -4,12 +4,7 @@
     <!-- 双下拉框头部 -->
     <div class="w-100% flex costume-header">
       <!-- 第一个下拉框 -->
-      <Dropdown
-        class="flex-grow-1 costume-header_left"
-        :trigger="['click']"
-        :bordered="false"
-        @open-change="visible1 = $event"
-      >
+      <Dropdown class="flex-grow-1 costume-header_left" :trigger="['click']" :bordered="false" @open-change="visible1 = $event">
         <div class="flex-basis-100% flex flex-items-center" @click.prevent>
           <component :is="getIcon(selectorConfig1.icon)" class="w-30px" />
           <div class="w-100px flex-grow-1 overflow-hidden whitespace-nowrap text-ellipsis">
@@ -19,7 +14,7 @@
           <CaretDownOutlined class="w-30px" v-else />
         </div>
         <template #overlay>
-          <Menu :selected-keys="[selectorConfig1.options]" @click="handleSelect1">
+          <Menu :selected-keys="[selectedValue1]" @click="handleSelect1">
             <MenuItem v-for="item in selectorConfig1.options" :key="item.value" :title="item.label">
               {{ item.label }}
             </MenuItem>
@@ -28,12 +23,7 @@
       </Dropdown>
 
       <!-- 第二个下拉框 -->
-      <Dropdown
-        class="flex-grow-1 costume-header_left"
-        :trigger="['click']"
-        :bordered="false"
-        @open-change="visible2 = $event"
-      >
+      <Dropdown class="flex-grow-1 costume-header_left" :trigger="['click']" :bordered="false" @open-change="visible2 = $event">
         <div class="flex-basis-100% flex flex-items-center" @click.prevent>
           <component :is="getIcon(selectorConfig2.icon)" class="w-30px" />
           <div class="w-100px flex-grow-1 overflow-hidden whitespace-nowrap text-ellipsis">
@@ -43,7 +33,7 @@
           <CaretDownOutlined class="w-30px" v-else />
         </div>
         <template #overlay>
-          <Menu :selected-keys="[selectorConfig2.options]" @click="handleSelect2">
+          <Menu :selected-keys="[selectedValue2]" @click="handleSelect2">
             <MenuItem v-for="item in selectorConfig2.options" :key="item.value" :title="item.label">
               {{ item.label }}
             </MenuItem>
@@ -53,185 +43,172 @@
     </div>
 
     <!-- 图表内容区域 -->
-    <div class="chart-container h-calc(100% - 30px)">
-      <CustomChart 
-        class="content__module" 
-        :chart-config="config.chartConfig" 
-        :chart-data="filteredChartData" 
-      />
+    <div class="chart-container h-190px">
+      <CustomChart class="content__module" :chart-config="chartConfig" :chart-data="chartData" height="100%" />
     </div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref, computed, watch, defineAsyncComponent } from 'vue';
-import { MenuItem, Menu, Dropdown } from 'ant-design-vue';
-import { 
-  SwapOutlined, 
-  CaretUpOutlined, 
-  CaretDownOutlined,
-  BarChartOutlined,
-  LineChartOutlined,
-  PieChartOutlined
-} from '@ant-design/icons-vue';
-import { getData, getFormattedText } from '../../hooks/helper';
-
-// 异步导入图表组件,优化加载性能
-const CustomChart = defineAsyncComponent(() => import('../detail/CustomChart.vue'));
-
-// 定义组件属性
-const props = defineProps<{
-  moduleData: any;
-  data: any;
-  config: any;
-}>();
-
-console.log('SelectorDualChart props:', props);
-
-// 状态管理
-const visible1 = ref(false);
-const visible2 = ref(false);
-const selectedValue1 = ref('');
-const selectedValue2 = ref('');
-const selectedLabel1 = ref('请选择');
-const selectedLabel2 = ref('请选择');
-
-// 从配置中获取选择器配置
-const { selectorConfig1, selectorConfig2 } = props.config.config;
-
-// 初始化选项数据
-const options1 = ref<any[]>([]);
-const options2 = ref<any[]>([]);
-
-// 处理图标渲染
-const getIcon = (iconName: string) => {
-  const iconMap: Record<string, any> = {
-    'swap': SwapOutlined,
-    'bar-chart': BarChartOutlined,
-    'line-chart': LineChartOutlined,
-    'pie-chart': PieChartOutlined,
-    // 可以添加更多图标映射
+  import { ref, onMounted, computed, watch, nextTick } from 'vue';
+  import { MenuItem, Menu, Dropdown } from 'ant-design-vue';
+  import { SwapOutlined, CaretUpOutlined, CaretDownOutlined, BarChartOutlined, LineChartOutlined, PieChartOutlined } from '@ant-design/icons-vue';
+  import { getData } from '../../hooks/helper';
+  import CustomChart from '../detail/CustomChart.vue';
+
+  // 定义组件属性
+  const props = defineProps<{
+    moduleData: any;
+    data: any;
+    config: any;
+  }>();
+
+  // 状态管理
+  const visible1 = ref(false);
+  const visible2 = ref(false);
+  const selectedValue1 = ref('');
+  const selectedValue2 = ref('');
+  const selectedLabel1 = ref('');
+  const selectedLabel2 = ref('');
+
+  // 从配置中获取选择器配置
+  const { chartConfig, selectorConfig1, selectorConfig2 } = props.config.config;
+
+  // 初始化选项数据
+  const options1 = ref<any[]>([]);
+  const options2 = ref<any[]>([]);
+  const rawChartData = ref([]); // 存储原始数据,用于过滤
+
+  // 处理图标渲染
+  const getIcon = (iconName: string) => {
+    const iconMap: Record<string, any> = {
+      swap: SwapOutlined,
+      'bar-chart': BarChartOutlined,
+      'line-chart': LineChartOutlined,
+      'pie-chart': PieChartOutlined,
+      // 可以添加更多图标映射
+    };
+    return iconMap[iconName] || SwapOutlined;
   };
-  return iconMap[iconName] || SwapOutlined;
-};
-
-// 获取图表配置
-const chartConfig = computed(() => {
-  // 从模块数据中找到图表配置
-  return props.moduleData.chart?.[0] || {};
-});
-
-// 初始化数据
-const initData = (data: any) => {
-  console.log('Initializing data with:', data);
-  // 从数据中获取第一个选择器的选项
-  // const rawOptions1 = getData(data, selectorConfig1.readFrom) || [];
-  options1.value = Array.isArray(selectorConfig1) ? selectorConfig1 : [selectorConfig1];
-  
-  // 从数据中获取第二个选择器的选项
-  // const rawOptions2 = getData(data, selectorConfig2.readFrom) || [];
-  options2.value = Array.isArray(selectorConfig2) ? selectorConfig2 : [selectorConfig2];
-  
+
   // 设置默认选中项
-  if (options1.value.length > 0) {
-    selectedValue1.value = options1.value[0].value;
-    selectedLabel1.value = options1.value[0].label;
+  const setDefaultSelections = () => {
+    // 设置第一个下拉框默认选中第一项
+    if (options1.value.length > 0) {
+      const firstOption1 = options1.value[0];
+      selectedValue1.value = firstOption1.value;
+      selectedLabel1.value = firstOption1.label;
+    }
+
+    // 设置第二个下拉框默认选中第一项
+    if (options2.value.length > 0) {
+      const firstOption2 = options2.value[0];
+      selectedValue2.value = firstOption2.value;
+      selectedLabel2.value = firstOption2.label;
+    }
+  };
+
+  // 组件挂载时初始化一次
+  onMounted(() => {
+    initData();
+    // 设置默认选中项
+    setDefaultSelections();
+  });
+
+  // 初始化数据
+  const initData = () => {
+    // 从数据中获取第一个选择器的选项
+    options1.value = selectorConfig1.options || [];
+    // 从数据中获取第二个选择器的选项
+    options2.value = selectorConfig2.options || [];
+
+    if (props.data) {
+      rawChartData.value = getData(props.data, chartConfig.readFrom, chartConfig.parser);
+    }
+  };
+
+  // 处理第一个下拉框选择
+  const handleSelect1 = (info: { key: string | number }) => {
+    const key = String(info.key);
+    selectedValue1.value = key;
+    const selectedItem = options1.value.find((item) => item.value === key);
+    if (selectedItem) {
+      selectedLabel1.value = selectedItem.label;
+    }
+  };
+
+  // 处理第二个下拉框选择
+  const handleSelect2 = (info: { key: string | number }) => {
+    const key = String(info.key);
+    selectedValue2.value = key;
+    const selectedItem = options2.value.find((item) => item.value === key);
+    if (selectedItem) {
+      selectedLabel2.value = selectedItem.label;
+    }
+  };
+
+  // 根据两个选择器的值过滤图表数据
+  const chartData = computed(() => {
+    // 如果没有原始数据,直接返回空
+    if (!rawChartData.value.length) return [];
+
+    // 过滤逻辑:使用选中的值过滤
+    return rawChartData.value.filter((item: any) => {
+      const matchFirst = item.deviceType === selectedValue1.value;
+      const matchSecond = item.deviceId === selectedValue2.value;
+      return matchFirst && matchSecond;
+    });
+  });
+
+  // 监听数据变化,重新初始化
+  watch(
+    () => props.data,
+    () => {
+      nextTick(() => {
+        initData();
+      });
+    },
+    { immediate: true }
+  );
+</script>
+
+<style scoped>
+  @import '/@/design/theme.less';
+
+  .selector-dual-chart {
+    height: 100%;
   }
-  
-  if (options2.value.length > 0) {
-    selectedValue2.value = options2.value[0].value;
-    selectedLabel2.value = options2.value[0].label;
+
+  .costume-header {
+    height: 30px;
+    background-image: linear-gradient(90deg, var(--vent-base-light-bg-opcity), transparent 20%, transparent 80%, var(--vent-base-light-bg-opcity));
   }
-};
-
-// 处理第一个下拉框选择
-const handleSelect1 = (info: { key: string | number }) => {
-  const key = String(info.key);
-  selectedValue1.value = key;
-  const selectedItem = options1.value.find(item => item.value === key);
-  if (selectedItem) {
-    selectedLabel1.value = selectedItem.label;
+
+  .costume-header_left {
+    border-left: 3px solid;
+    border-right: 3px solid;
+    border-image-source: linear-gradient(to top, #00000033, var(--vent-base-light-bg), #00000033);
+    border-image-slice: 1;
   }
-};
-
-// 处理第二个下拉框选择
-const handleSelect2 = (info: { key: string | number }) => {
-  const key = String(info.key);
-  selectedValue2.value = key;
-  const selectedItem = options2.value.find(item => item.value === key);
-  if (selectedItem) {
-    selectedLabel2.value = selectedItem.label;
+
+  .chart-container {
+    width: 100%;
+    overflow: hidden;
   }
-};
-
-// 根据两个选择器的值过滤图表数据
-const filteredChartData = computed(() => {
-  if (!props.data) return [];
-  
-  // 示例:同时满足两个选择器的筛选条件
-  // return props.data.filter((item: any) => {
-  //   return item[selectorConfig1.basis] === selectedValue1.value &&
-  //          item[selectorConfig2.basis] === selectedValue2.value;
-  // });
-});
-
-// 监听数据变化,重新初始化
-watch(
-  () => props.data,
-  (newData) => {
-    initData(newData);
-  },
-  { immediate: true }
-);
-
-// 监听选择变化,更新图表数据
-watch(
-  [() => selectedValue1.value, () => selectedValue2.value],
-  () => {
-    // emit('update:chartData', filteredChartData.value);
+
+  ::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
+    color: #fff;
   }
-);
-</script>
 
-<style scoped>
-@import '/@/design/theme.less';
-
-.selector-dual-chart {
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-}
-
-.costume-header {
-  height: 30px;
-  background-image: linear-gradient(90deg, var(--vent-base-light-bg-opcity), transparent 20%, transparent 80%, var(--vent-base-light-bg-opcity));
-}
-
-.costume-header_left {
-  border-left: 3px solid;
-  border-right: 3px solid;
-  border-image-source: linear-gradient(to top, #00000033, var(--vent-base-light-bg), #00000033);
-  border-image-slice: 1;
-}
-
-.chart-container {
-  width: 100%;
-  overflow: hidden;
-}
-
-::v-deep .zxm-select:not(.zxm-select-customize-input) .zxm-select-selector {
-  color: #fff;
-}
-
-::v-deep .zxm-select-arrow {
-  color: #fff;
-}
-
-::v-deep .zxm-select-selection-item {
-  color: #fff !important;
-}
-
-::v-deep .zxm-select-selection-placeholder {
-  color: #fff !important;
-}
-</style>
+  ::v-deep .zxm-select-arrow {
+    color: #fff;
+  }
+
+  ::v-deep .zxm-select-selection-item {
+    color: #fff !important;
+  }
+
+  ::v-deep .zxm-select-selection-placeholder {
+    color: #fff !important;
+  }
+</style>

+ 19 - 4
src/views/vent/home/configurable/configurable.api.ts

@@ -8,7 +8,8 @@ enum Api {
   getDisHome = '/monitor/disaster/getDisHome',
   getBDDustData = '/monitor/disaster/getDisDustHome',
   getBDFireData = '/monitor/disaster/getDisFireHome',
-  getDeviceSys = '/ventanaly-device/monitor/system',
+  getDeviceSys = '/ventanaly-device/monitor/getSysFireHomeInfo',
+  getAlarmRecord = '/ventanaly-device/safety/ventanalyAlarmLog/sysLinkDevAlarmLog',
 }
 
 // 搞这个缓存是由于:目前代码上的设计是多个模块发出多次请求,每个模块自己负责消费前者的响应。
@@ -215,7 +216,7 @@ export const getBDFireData = (params) => {
     return res;
   });
 };
-// ceshi
+// 塔山火灾预警页面获取数据接口
 export const getDeviceSys = (params) => {
   const key = `${Api.getDeviceSys}?${JSON.stringify(params)}`;
   if (!cache.has(key)) {
@@ -227,10 +228,24 @@ export const getDeviceSys = (params) => {
     );
   }
   return (cache.get(key) as Promise<any>).then((res) => {
-    console.log('getDeviceSys', res);
     return res;
   });
-}
+};
+
+export const getAlarmRecord = (params) => {
+  const key = `${Api.getAlarmRecord}?${JSON.stringify(params)}`;
+  if (!cache.has(key)) {
+    cache.set(
+      key,
+      defHttp.post({ url: Api.getAlarmRecord, params }).finally(() => {
+        cache.delete(key);
+      })
+    );
+  }
+  return (cache.get(key) as Promise<any>).then((res) => {
+    return res;
+  });
+};
 
 export const getDisHome = (params) => {
   const key = `${Api.getDisHome}?${JSON.stringify(params)}`;

+ 223 - 310
src/views/vent/home/configurable/configurable.data.tashan.ts

@@ -1,7 +1,6 @@
 import type { Config } from '../../deviceManager/configurationTable/types';
 
 export const testConfigTSFire: Config[] = [
-
   // 1. 采空区基本信息(左上)
   {
     deviceType: 'goafsInfo',
@@ -49,7 +48,7 @@ export const testConfigTSFire: Config[] = [
             {
               label: '采空区管理',
               value: '${goafManage}',
-            }
+            },
           ],
         },
       ],
@@ -61,10 +60,10 @@ export const testConfigTSFire: Config[] = [
       preset: [],
     },
     showStyle: {
-    size: 'width:440px;height:250px;',
-    version: '原版',
-    position: 'top:70px;left:10px;',
-    headerPosition: 'centerBottom',
+      size: 'width:440px;height:250px;',
+      version: '原版',
+      position: 'top:70px;left:10px;',
+      headerPosition: 'centerBottom',
     },
   },
   // 2. 矿用自动喷洒系统(左中)
@@ -99,8 +98,8 @@ export const testConfigTSFire: Config[] = [
           },
           {
             name: 'board',
-            basis: '60%'
-          }
+            basis: '60%',
+          },
         ],
       },
       board: [
@@ -124,7 +123,7 @@ export const testConfigTSFire: Config[] = [
             {
               label: '液位计',
               value: '液位超限',
-            }
+            },
           ],
         },
       ],
@@ -137,12 +136,12 @@ export const testConfigTSFire: Config[] = [
       preset: [
         {
           readFrom: 'select_cs',
-          setLabelConfig :{
-            selectL:'请选择...',
-            switchL:['开启','关闭'],
-            switchL1:'进料泵',
-            switchL2:'注浆泵'
-          }
+          setLabelConfig: {
+            selectL: '请选择...',
+            switchL: ['开启', '关闭'],
+            switchL1: '进料泵',
+            switchL2: '注浆泵',
+          },
         },
       ],
       mock: {},
@@ -155,16 +154,16 @@ export const testConfigTSFire: Config[] = [
   },
   // 3. 光纤测温系统(左下)
   {
-    deviceType: 'fiber',
+    deviceType: 'deviceInfo',
     moduleName: '光纤测温系统',
     pageType: 'ts_fire',
     moduleData: {
       header: {
         show: true,
-        readFrom: 'deviceInfo.fiber',
+        readFrom: 'fiber.datalist',
         selector: {
           show: true,
-          value: '${strname}',
+          value: '${strinstallpos}',
         },
         slot: {
           show: false,
@@ -179,23 +178,24 @@ export const testConfigTSFire: Config[] = [
       layout: {
         direction: 'column',
         items: [
-        {
-        name: 'chart',
-        basis: '100%',
-        },
+          {
+            name: 'chart',
+            basis: '100%',
+          },
         ],
       },
       chart: [
         {
           type: 'line_smooth',
-          readFrom: 'arrayFiber',
-          legend: { show: false },
+          readFrom: 'readData.fibreTemperature',
+          parser: 'json',
+          legend: { show: true },
           xAxis: [{ show: true }],
           yAxis: [{ show: true, name: '温度(℃)', position: 'left' }],
           series: [
             {
               label: '${strinstallpos}',
-              readFrom: 'fibreTemperatureArr',
+              readFrom: '',
               xprop: 'pos',
               yprop: 'value',
             },
@@ -243,8 +243,8 @@ export const testConfigTSFire: Config[] = [
         direction: 'row',
         items: [
           {
-          name: 'table',
-          basis: '100%',
+            name: 'table',
+            basis: '100%',
           },
         ],
       },
@@ -255,32 +255,31 @@ export const testConfigTSFire: Config[] = [
       table: [
         {
           type: 'A',
+          parser: 'json',
           readFrom: 'sysInfo.coalSpoCha',
           columns: [
             {
               name: '煤层',
-              prop: '${mc}',
+              prop: 'mc',
             },
             {
               name: '自燃倾向性',
-              prop: '${zrqxx}',
+              prop: 'zrqxx',
             },
             {
               name: '最短发火期',
-              prop: '${zdfhq}',
+              prop: 'zdfhq',
             },
             {
               name: '自燃倾向等级',
-              prop: '${zrqxxdj}',
-            }
+              prop: 'zrqxxdj',
+            },
           ],
         },
       ],
       list: [],
       complex_list: [],
       preset: [],
-      mock: {
-      },
     },
     showStyle: {
       size: 'width:440px;height:200px;',
@@ -299,9 +298,9 @@ export const testConfigTSFire: Config[] = [
       layout: {
         direction: 'column',
         items: [
-          { 
-            name: 'partition', 
-            basis: 'auto' ,
+          {
+            name: 'partition',
+            basis: 'auto',
             overflow: false,
           },
           {
@@ -309,36 +308,36 @@ export const testConfigTSFire: Config[] = [
             basis: 'auto',
             overflow: false,
           },
-          { 
-            name: 'partition', 
-            basis: 'auto' ,
+          {
+            name: 'partition',
+            basis: 'auto',
             overflow: false,
           },
-          { 
-            name: 'board', 
-            basis: 'auto' ,
+          {
+            name: 'board',
+            basis: 'auto',
             overflow: false,
           },
-          { 
-            name: 'partition', 
-            basis: 'auto' ,
+          {
+            name: 'partition',
+            basis: 'auto',
             overflow: false,
           },
-          { 
-            name: 'board', 
+          {
+            name: 'board',
             basis: 'auto',
             overflow: false,
           },
-          { 
-            name: 'partition', 
+          {
+            name: 'partition',
             basis: 'auto',
             overflow: false,
           },
-          { 
-            name: 'board', 
+          {
+            name: 'board',
             basis: 'auto',
             overflow: false,
-          }
+          },
         ],
       },
       table: [],
@@ -347,7 +346,7 @@ export const testConfigTSFire: Config[] = [
           type: 'N',
           readFrom: '',
           layout: 'label-top',
-            items: [
+          items: [
             {
               label: '流量',
               value: '${cumulativeFlow}',
@@ -363,7 +362,7 @@ export const testConfigTSFire: Config[] = [
             {
               label: '氮含量',
               value: '${nitrogenContent}',
-            }
+            },
           ],
         },
         {
@@ -382,7 +381,7 @@ export const testConfigTSFire: Config[] = [
             {
               label: '油压',
               value: '0.99',
-            }
+            },
           ],
         },
         {
@@ -401,7 +400,7 @@ export const testConfigTSFire: Config[] = [
             {
               label: '油压',
               value: '0.99',
-            }
+            },
           ],
         },
         {
@@ -420,9 +419,9 @@ export const testConfigTSFire: Config[] = [
             {
               label: '油压',
               value: '0.99',
-            }
+            },
           ],
-        }
+        },
       ],
       chart: [],
       gallery: [],
@@ -436,28 +435,28 @@ export const testConfigTSFire: Config[] = [
           readFrom: '',
           layout: 'icon-pre',
           label: '制氮机',
-          icon:'/src/assets/images/home-container/configurable/tashanhome/partition-icon-1.png'
+          icon: '/src/assets/images/home-container/configurable/tashanhome/partition-icon-1.png',
         },
         {
           type: 'A',
           readFrom: '',
           layout: 'icon-pre',
           label: '风压机#1',
-          icon:'/src/assets/images/home-container/configurable/tashanhome/partition-icon-2.png'
+          icon: '/src/assets/images/home-container/configurable/tashanhome/partition-icon-2.png',
         },
         {
           type: 'A',
           readFrom: '',
           layout: 'icon-pre',
           label: '风压机#2',
-          icon:'/src/assets/images/home-container/configurable/tashanhome/partition-icon-2.png'
+          icon: '/src/assets/images/home-container/configurable/tashanhome/partition-icon-2.png',
         },
         {
           type: 'A',
           readFrom: '',
           layout: 'icon-pre',
           label: '风压机#3',
-          icon:'/src/assets/images/home-container/configurable/tashanhome/partition-icon-2.png'
+          icon: '/src/assets/images/home-container/configurable/tashanhome/partition-icon-2.png',
         },
       ],
       mock: {},
@@ -470,21 +469,21 @@ export const testConfigTSFire: Config[] = [
   },
   // 6. 采空区密闭监测系统(右下)
   {
-    deviceType: 'pdArray',
+    deviceType: 'goafMonitoring',
     moduleName: '采空区密闭监测系统',
     pageType: 'ts_fire',
     moduleData: {
       header: {
-      show: false,
-      readFrom: '',
-      selector: {
-        show: true,
-        value: '${systemname}',
-      },
-      slot: {
         show: false,
-        value: '',
-      },
+        readFrom: '',
+        selector: {
+          show: false,
+          value: '',
+        },
+        slot: {
+          show: false,
+          value: '',
+        },
       },
       background: {
         show: false,
@@ -500,126 +499,128 @@ export const testConfigTSFire: Config[] = [
           },
         ],
       },
-      chart: [
-        {
-          type: 'line_smooth',
-          readFrom: 'mockChart',
-          legend: { show: false },
-          xAxis: [{ show: true }],
-          yAxis: [{ show: true, name: '温度(℃)', position: 'left' }],
-          series: [
-            {
-              label: '',
-              readFrom: 'seriesData',
-              xprop: 'pos',
-              yprop: 'value',
-            },
-          ],
-        },
-      ],
+      chart: [],
       gallery: [],
       gallery_list: [],
       table: [],
       list: [],
       complex_list: [],
       preset: [
-        // {
-        //   readFrom: '',
-        //   selectorConfig1: {
-        //     options:[
-        //       {
-        //         value: 'o2',
-        //         label: '氧气',
-        //       },
-        //       {
-        //         value: 'co',
-        //         label: '一氧化碳',
-        //       }
-        //     ]
-
-        //   },
-        //   selectorConfig2: {
-        //     options:[
-        //       {
-        //         value: '1',
-        //         label: '工作面1',
-        //       },
-        //       {
-        //         value: '1',
-        //         label: '工作面2',
-        //       }
-        //     ],
-        //   }
-        // },
+        {
+          readFrom: '',
+          selectorConfig2: {
+            options: [
+              {
+                value: 'o2',
+                label: '氧气',
+              },
+              {
+                value: 'co',
+                label: '一氧化碳',
+              },
+            ],
+          },
+          selectorConfig1: {
+            options: [
+              {
+                value: '1',
+                label: '工作面1',
+              },
+              {
+                value: '2',
+                label: '工作面2',
+              },
+            ],
+          },
+          chartConfig: {
+            clear: true,
+            type: 'line_smooth',
+            readFrom: 'mockChart',
+            legend: { show: true },
+            xAxis: [{ show: true }],
+            yAxis: [{ show: true, name: '', position: 'left' }],
+            series: [
+              {
+                label: '${label}',
+                readFrom: 'seriesData',
+                xprop: 'pos',
+                yprop: 'value',
+              },
+            ],
+          },
+        },
       ],
-      mock:{
-        // mockChart:[
-        //   {
-        //     deviceType:'o2',
-        //     deviceId:'1',
-        //     seriesData:[
-        //       { pos: '0', value: 10 },
-        //       { pos: '10', value: 12 },
-        //       { pos: '20', value: 11 },
-        //       { pos: '30', value: 13 },
-        //       { pos: '40', value: 14 },
-        //       { pos: '50', value: 16 },
-        //       { pos: '60', value: 15 },
-        //       { pos: '70', value: 17 },
-        //       { pos: '80', value: 18 },
-        //       { pos: '90', value: 19 },
-        //     ]
-        //   },
-        //   {
-        //     deviceType:'co',
-        //     deviceId:'2',
-        //     seriesData:[
-        //       { pos: '0', value: 30 },
-        //       { pos: '10', value: 32 },
-        //       { pos: '20', value: 31 },
-        //       { pos: '30', value: 33 },
-        //       { pos: '40', value: 34 },
-        //       { pos: '50', value: 36 },
-        //       { pos: '60', value: 35 },
-        //       { pos: '70', value: 37 },
-        //       { pos: '80', value: 38 },
-        //       { pos: '90', value: 39 },
-        //     ]
-        //   },
-        //   {
-        //     deviceType:'o2',
-        //     deviceId:'1',
-        //     seriesData:[
-        //       { pos: '0', value: 40 },
-        //       { pos: '10', value: 42 },
-        //       { pos: '20', value: 41 },
-        //       { pos: '30', value: 43 },
-        //       { pos: '40', value: 44 },
-        //       { pos: '50', value: 46 },
-        //       { pos: '60', value: 45 },
-        //       { pos: '70', value: 47 },
-        //       { pos: '80', value: 48 },
-        //       { pos: '90', value: 49 },
-        //     ]
-        //   },
-        //   {
-        //     deviceType:'co',
-        //     deviceId:'2',
-        //     seriesData:[
-        //       { pos: '0', value: 60 },
-        //       { pos: '10', value: 62 },
-        //       { pos: '20', value: 61 },
-        //       { pos: '30', value: 63 },
-        //       { pos: '40', value: 64 },
-        //       { pos: '50', value: 66 },
-        //       { pos: '60', value: 65 },
-        //       { pos: '70', value: 67 },
-        //       { pos: '80', value: 68 },
-        //       { pos: '90', value: 69 },
-        //     ]
-        //   }
-
-        // ]
+      mock: {
+        mockChart: [
+          {
+            label: '工作面1氧气',
+            deviceId: 'o2',
+            deviceType: '1',
+            seriesData: [
+              { pos: '0', value: 21 },
+              { pos: '10', value: 21 },
+              { pos: '20', value: 21 },
+              { pos: '30', value: 21 },
+              { pos: '40', value: 21 },
+              { pos: '50', value: 21 },
+              { pos: '60', value: 21 },
+              { pos: '70', value: 21 },
+              { pos: '80', value: 21 },
+              { pos: '90', value: 21 },
+            ],
+          },
+          {
+            label: '工作面1一氧化碳',
+            deviceId: 'co',
+            deviceType: '1',
+            seriesData: [
+              { pos: '0', value: 11 },
+              { pos: '10', value: 11 },
+              { pos: '20', value: 11 },
+              { pos: '30', value: 11 },
+              { pos: '40', value: 11 },
+              { pos: '50', value: 11 },
+              { pos: '60', value: 11 },
+              { pos: '70', value: 11 },
+              { pos: '80', value: 11 },
+              { pos: '90', value: 11 },
+            ],
+          },
+          {
+            label: '工作面2氧气',
+            deviceId: 'o2',
+            deviceType: '2',
+            seriesData: [
+              { pos: '0', value: 25 },
+              { pos: '10', value: 25 },
+              { pos: '20', value: 25 },
+              { pos: '30', value: 25 },
+              { pos: '40', value: 25 },
+              { pos: '50', value: 25 },
+              { pos: '60', value: 25 },
+              { pos: '70', value: 25 },
+              { pos: '80', value: 25 },
+              { pos: '90', value: 25 },
+            ],
+          },
+          {
+            label: '工作面2一氧化碳',
+            deviceId: 'co',
+            deviceType: '2',
+            seriesData: [
+              { pos: '0', value: 15 },
+              { pos: '10', value: 15 },
+              { pos: '20', value: 15 },
+              { pos: '30', value: 15 },
+              { pos: '40', value: 15 },
+              { pos: '50', value: 15 },
+              { pos: '60', value: 15 },
+              { pos: '70', value: 15 },
+              { pos: '80', value: 15 },
+              { pos: '90', value: 15 },
+            ],
+          },
+        ],
       },
     },
     showStyle: {
@@ -658,7 +659,6 @@ export const testConfigTSFire: Config[] = [
             name: 'table',
             basis: '100%',
           },
-
         ],
       },
       board: [],
@@ -668,50 +668,23 @@ export const testConfigTSFire: Config[] = [
       table: [
         {
           type: 'A',
-          readFrom: 'mockTable',
+          readFrom: 'deviceInfo.bundletube.enterWind',
           columns: [
-            { name: '序号', prop: 'serialVal' },
-            { name: '监测点', prop: 'MonitorPoint' },
-            { name: '报警等级', prop: 'warnLevel' },
-            { name: '类型', prop: 'warnType' },
-            { name: '值', prop: 'nowVal' },
+            { name: '监测点', prop: 'strinstallpos' },
+            { name: '温度', prop: 'readData.temperature' },
+            { name: 'ch2', prop: 'readData.ch2val' },
+            { name: 'ch', prop: 'readData.chval' },
+            { name: 'co2', prop: 'readData.co2val' },
+            { name: 'co', prop: 'readData.coval' },
+            { name: 'gas', prop: 'readData.gasval' },
+            { name: 'o2', prop: 'readData.o2val' },
+            { name: '报警等级', prop: 'syswarnLevel_str' },
           ],
-        },],
+        },
+      ],
       list: [],
       complex_list: [],
       preset: [],
-      mock: {
-        mockTable: [
-          {
-            serialVal: '1',
-            MonitorPoint: '130608工作面采空区1',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '2',
-            MonitorPoint: '130608工作面采空区1',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '3',
-            MonitorPoint: '130608工作面采空区1',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '4',
-            MonitorPoint: '130608工作面采空区1',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          }
-        ],
-      },
     },
     showStyle: {
       size: 'width:980px;height:270px;',
@@ -719,10 +692,10 @@ export const testConfigTSFire: Config[] = [
       position: 'bottom:8px;left:470px',
     },
   },
-  // 8. 风侧设备监测(中下2)
+  // 8. 风侧设备监测(中下2)
   {
     deviceType: 'RealtimeMonitor',
-    moduleName: '风侧设备监测',
+    moduleName: '风侧设备监测',
     pageType: 'ts_fire',
     moduleData: {
       header: {
@@ -749,7 +722,6 @@ export const testConfigTSFire: Config[] = [
             name: 'table',
             basis: '100%',
           },
-
         ],
       },
       board: [],
@@ -759,50 +731,23 @@ export const testConfigTSFire: Config[] = [
       table: [
         {
           type: 'A',
-          readFrom: 'mockTable',
+          readFrom: 'deviceInfo.bundletube.returnWind',
           columns: [
-            { name: '序号', prop: 'serialVal' },
-            { name: '监测点', prop: 'MonitorPoint' },
-            { name: '报警等级', prop: 'warnLevel' },
-            { name: '类型', prop: 'warnType' },
-            { name: '值', prop: 'nowVal' },
+            { name: '监测点', prop: 'strinstallpos' },
+            { name: '温度', prop: 'readData.temperature' },
+            { name: 'ch2', prop: 'readData.ch2val' },
+            { name: 'ch', prop: 'readData.chval' },
+            { name: 'co2', prop: 'readData.co2val' },
+            { name: 'co', prop: 'readData.coval' },
+            { name: 'gas', prop: 'readData.gasval' },
+            { name: 'o2', prop: 'readData.o2val' },
+            { name: '报警等级', prop: 'syswarnLevel_str' },
           ],
-        },],
+        },
+      ],
       list: [],
       complex_list: [],
       preset: [],
-      mock: {
-        mockTable: [
-          {
-            serialVal: '1',
-            MonitorPoint: '130608工作面采空区2',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '2',
-            MonitorPoint: '130608工作面采空区2',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '3',
-            MonitorPoint: '130608工作面采空区2',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '4',
-            MonitorPoint: '130608工作面采空区2',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          }
-        ],
-      },
     },
     showStyle: {
       size: 'width:980px;height:270px;',
@@ -840,7 +785,6 @@ export const testConfigTSFire: Config[] = [
             name: 'table',
             basis: '100%',
           },
-
         ],
       },
       board: [],
@@ -850,55 +794,24 @@ export const testConfigTSFire: Config[] = [
       table: [
         {
           type: 'A',
-          readFrom: 'mockTable',
+          readFrom: 'alarmLog',
           columns: [
-            { name: '序号', prop: 'serialVal' },
-            { name: '监测点', prop: 'MonitorPoint' },
-            { name: '报警等级', prop: 'warnLevel' },
-            { name: '类型', prop: 'warnType' },
-            { name: '值', prop: 'nowVal' },
+            { name: '设备名称', prop: 'devicename' },
+            { name: '预警描述', prop: 'devicekind_dictText' },
+            { name: '预警值名称', prop: 'valuename' },
+            { name: '报警等级', prop: 'nwartype_dictText' },
+            { name: '值', prop: 'val' },
           ],
-        },],
+        },
+      ],
       list: [],
       complex_list: [],
       preset: [],
-      mock: {
-        mockTable: [
-          {
-            serialVal: '1',
-            MonitorPoint: '130608工作面采空区3',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '2',
-            MonitorPoint: '130608工作面采空区3',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '3',
-            MonitorPoint: '130608工作面采空区3',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          },
-          {
-            serialVal: '4',
-            MonitorPoint: '130608工作面采空区3',
-            warnLevel: '低风险',
-            warnType: '乙烷',
-            nowVal: '0ppm',
-          }
-        ],
-      },
     },
     showStyle: {
       size: 'width:980px;height:270px;',
       version: '原版',
       position: 'bottom:8px;left:470px',
     },
-  }
-];
+  },
+];

+ 141 - 153
src/views/vent/home/configurable/fireMine.vue

@@ -12,11 +12,9 @@
         <div>
           <img src="@/assets/images/home-container/configurable/minehome/znzjxt-icon.png" alt="智能注浆系统" />
         </div>
-        <div>
-          智能注浆系统
-        </div>
+        <div> 智能注浆系统 </div>
       </div>
-      <div class="center-info-content ">
+      <div class="center-info-content">
         <div class="center-info-block left">
           <img src="@/assets/images/home-container/configurable/minehome/jcqy-icon.png" alt="监测区域" />
           <span>监测区域</span>
@@ -34,15 +32,13 @@
         <div>
           <img src="@/assets/images/home-container/configurable/minehome/znzdxt-icon.png" alt="智能注氮系统" />
         </div>
-        <div>
-          智能注氮系统
-        </div>
+        <div> 智能注氮系统 </div>
       </div>
     </div>
     <!-- 渲染所有模块 -->
     <ModuleMine
       v-for="cfg in cfgs"
-       :key="cfg.deviceType + cfg.moduleName"
+      :key="cfg.deviceType + cfg.moduleName"
       :show-style="cfg.showStyle"
       :module-data="cfg.moduleData"
       :module-name="cfg.moduleName"
@@ -65,177 +61,169 @@
   </div>
 </template>
 <script lang="ts" setup>
-import { computed, onMounted, onUnmounted } from 'vue';
-import { useInitConfigs, useInitPage } from './hooks/useInit';
-import ModuleMine from './components/ModuleMine.vue';
-import ModuleBDDual from './components/ModuleBDDual.vue';
-import NewNav from './components/originalNew/NewNavFire.vue';
-import { getDisHome } from './configurable.api';
-import { testConfigMineFire } from './configurable.data.mine';
+  import { computed, onMounted, onUnmounted } from 'vue';
+  import { useInitConfigs, useInitPage } from './hooks/useInit';
+  import ModuleMine from './components/ModuleMine.vue';
+  import ModuleBDDual from './components/ModuleBDDual.vue';
+  import NewNav from './components/originalNew/NewNavFire.vue';
+  import { getDisHome } from './configurable.api';
+  import { testConfigMineFire } from './configurable.data.mine';
 
-const cfgs = computed(() =>
-  configs.value.filter((_, index) => index !== 6 && index !== 7)
-);
-const cfgA = computed<any>(() =>
-  configs.value[6]
-);
-const cfgB = computed<any>(() =>
-  configs.value[7]
-);
-const { configs, devicesTypes, fetchConfigs } = useInitConfigs();
-const { mainTitle, data, updateData } = useInitPage('矿井火灾预警系统');
-let interval: ReturnType<typeof setInterval> | undefined;
+  const cfgs = computed(() => configs.value.filter((_, index) => index !== 6 && index !== 7));
+  const cfgA = computed<any>(() => configs.value[6]);
+  const cfgB = computed<any>(() => configs.value[7]);
+  const { configs, devicesTypes, fetchConfigs } = useInitConfigs();
+  const { mainTitle, data, updateData } = useInitPage('矿井火灾预警系统');
+  let interval: ReturnType<typeof setInterval> | undefined;
 
-onMounted(() => {
-  fetchConfigs('mine_fire').then(() => {
-    configs.value = testConfigMineFire;
-    getDisHome({
-      dataList: devicesTypes.value.concat('fireAllMineWarn').join(','),
-    }).then(updateData);
+  onMounted(() => {
+    fetchConfigs('mine_fire').then(() => {
+      configs.value = testConfigMineFire;
+      getDisHome({
+        dataList: devicesTypes.value.concat('fireAllMineWarn').join(','),
+      }).then(updateData);
+    });
+    interval = setInterval(() => {
+      getDisHome({
+        dataList: devicesTypes.value.concat('fireAllMineWarn').join(','),
+      }).then(updateData);
+    }, 2000);
   });
-  interval = setInterval(() => {
-    getDisHome({
-      dataList: devicesTypes.value.concat('fireAllMineWarn').join(','),
-    }).then(updateData);
-  }, 2000);
-});
 
-onUnmounted(() => {
-  clearInterval(interval);
-});
-function redirectTo(url) {
-  window.open(url);
-}
+  onUnmounted(() => {
+    clearInterval(interval);
+  });
+  function redirectTo(url) {
+    window.open(url);
+  }
 </script>
 <style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@font-face {
-  font-family: 'douyuFont';
-  src: url('../../../../assets/font/douyuFont.otf');
-}
+  @import '/@/design/theme.less';
 
-.company-home {
-  --image-bg: url('@/assets/images/home-container/configurable/minehome/bg.png');
-  --image-fire-title: url(/@/assets/images/home-container/configurable/minehome/fire-title.png);
-  --image-common-border1: url('/@/assets/images/home-container/configurable/minehome/common-border1.png');
-  --image-common-border3: url('/@/assets/images/home-container/configurable/minehome/common-border3.png');
-  width: 100%;
-  height: 100%;
-  color: @white;
-  position: relative;
-  background: var(--image-bg) no-repeat center;
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
 
-  .top-bg {
+  .company-home {
+    --image-bg: url('@/assets/images/home-container/configurable/minehome/bg.png');
+    --image-fire-title: url(/@/assets/images/home-container/configurable/minehome/fire-title.png);
+    --image-common-border1: url('/@/assets/images/home-container/configurable/minehome/common-border1.png');
+    --image-common-border3: url('/@/assets/images/home-container/configurable/minehome/common-border3.png');
     width: 100%;
-    height: 73px;
-    background: var(--image-fire-title) no-repeat top;
-    position: absolute;
-    z-index: 1;
-    ::v-deep .New-nav .nav-menu .nav-menu-left .nav-menu-unactive{
-      margin-top: 0;
-    }
-    ::v-deep .New-nav .nav-menu .nav-menu-left .nav-menu-active{
-      margin-top: 0;
-    }
-    ::v-deep .New-nav .nav-menu .nav-menu-right .nav-menu-unactive{
-      margin-top: 0;
-    }
-    ::v-deep .New-nav .nav-menu .nav-menu-right .nav-menu-active{
-      margin-top: 0;
-    }
+    height: 100%;
+    color: @white;
+    position: relative;
+    background: var(--image-bg) no-repeat center;
 
-  }
-  // 顶部中间样式块
-  .center-info-bar {
-    position: absolute;
-    top: 80px;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 900px;
-    height: 90px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    z-index: 2;
-    background: url('@/assets/images/home-container/configurable/minehome/center-info-bg.png') no-repeat center;
-    padding: 0 20px;
-    gap: 15px;
-
-    .center-info-btn {
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      color: #fff;
-      font-size: 10px;
-      font-family: 'douyuFont';
-      font-weight: bold;
-      cursor: pointer;
-      user-select: none;
-      width: 110px;
-      margin: 0 0 10px 0;
-      img {
-        width: 60px;
+    .top-bg {
+      width: 100%;
+      height: 73px;
+      background: var(--image-fire-title) no-repeat top;
+      position: absolute;
+      z-index: 1;
+      ::v-deep .New-nav .nav-menu .nav-menu-left .nav-menu-unactive {
+        margin-top: 0;
+      }
+      ::v-deep .New-nav .nav-menu .nav-menu-left .nav-menu-active {
+        margin-top: 0;
+      }
+      ::v-deep .New-nav .nav-menu .nav-menu-right .nav-menu-unactive {
+        margin-top: 0;
+      }
+      ::v-deep .New-nav .nav-menu .nav-menu-right .nav-menu-active {
+        margin-top: 0;
       }
     }
-
-    .center-info-content {
+    // 顶部中间样式块
+    .center-info-bar {
+      position: absolute;
+      top: 80px;
+      left: 50%;
+      transform: translateX(-50%);
+      width: 900px;
+      height: 90px;
       display: flex;
       align-items: center;
       justify-content: center;
+      z-index: 2;
+      background: url('@/assets/images/home-container/configurable/minehome/center-info-bg.png') no-repeat center;
+      padding: 0 20px;
+      gap: 15px;
 
-      .center-info-block {
-        color: #ffffff;
-        font-size: 18px;
-        img{
-          margin: 0 5px;
-        }
-      }
-      .center-info-risk {
+      .center-info-btn {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
         color: #fff;
-        font-weight: bolder;
-        text-align: center;
-        .risk-level {
-          color: #4EABD9;
-          font-size: 24px;
-          font-weight: bold;
-          letter-spacing: 8px;
-          margin: 10px 0;
+        font-size: 10px;
+        font-family: 'douyuFont';
+        font-weight: bold;
+        cursor: pointer;
+        user-select: none;
+        width: 110px;
+        margin: 0 0 10px 0;
+        img {
+          width: 60px;
         }
       }
 
-      .left {
-        margin-right: 45px;
+      .center-info-content {
+        display: flex;
+        align-items: center;
+        justify-content: center;
 
-      }
-      .right {
-        margin-left: 45px;
+        .center-info-block {
+          color: #ffffff;
+          font-size: 18px;
+          img {
+            margin: 0 5px;
+          }
+        }
+        .center-info-risk {
+          color: #fff;
+          font-weight: bolder;
+          text-align: center;
+          .risk-level {
+            color: #4eabd9;
+            font-size: 24px;
+            font-weight: bold;
+            letter-spacing: 8px;
+            margin: 10px 0;
+          }
+        }
+
+        .left {
+          margin-right: 45px;
+        }
+        .right {
+          margin-left: 45px;
+        }
       }
     }
-  }
 
-  ::v-deep .dane-bd {
-    background-repeat: no-repeat;
-    background-position: center;
-    background-size: 100% 100%;
-    &.dane-w {
-      background-image: var(--image-common-border3);
-    }
-    .dane-title {
-      justify-content: space-around;
-      padding: 0 50px 0 0;
+    ::v-deep .dane-bd {
+      background-repeat: no-repeat;
+      background-position: center;
+      background-size: 100% 100%;
+      &.dane-w {
+        background-image: var(--image-common-border3);
+      }
+      .dane-title {
+        justify-content: space-around;
+        padding: 0 50px 0 0;
 
-      .common-navL {
-        font-size: 14px;
-        font-weight: bold;
-        font-family: 'douyuFont';
+        .common-navL {
+          font-size: 14px;
+          font-weight: bold;
+          font-family: 'douyuFont';
+        }
+      }
+      .dane-content {
+        border: none;
+        background: none;
+        padding: 5px 35px 10px 10px;
       }
-    }
-    .dane-content {
-      border: none;
-      background: none;
-      padding: 5px 35px 10px 10px;
     }
   }
-}
 </style>

+ 247 - 228
src/views/vent/home/configurable/fireTS.vue

@@ -9,47 +9,48 @@
     <div class="center-info-bar">
       <div class="left-info-content">
         <div class="left-block block1">
-          <div class="info-value">{{fireSgWarnInfo.sgCoTbAlarmAddress}}</div>
+          <div class="info-value">{{ fireSgWarnInfo.sgCoTbAlarmAddress }}</div>
           <div class="info-label">突变预警</div>
         </div>
         <div class="left-block block2">
-          <div class="info-value">{{fireSgWarnInfo.nyAlarmLevelStr}}</div>
+          <div class="info-value">{{ fireSgWarnInfo.nyAlarmLevelStr }}</div>
           <div class="info-label">煤自燃氧化阶段</div>
         </div>
         <div class="left-block block3">
-          <div class="info-value">{{fireSgWarnInfo.sgMaxTemp}}</div>
+          <div class="info-value">{{ fireSgWarnInfo.sgMaxTemp }}</div>
           <div class="info-label">最高温度</div>
         </div>
       </div>
       <div class="center-info-content">
-        <div class="info-value">{{fireSgWarnInfo.aqfxLevelStr}}</div>
+        <div class="info-value">{{ fireSgWarnInfo.aqfxLevelStr }}</div>
         <div class="info-label">火灾安全等级</div>
       </div>
       <div class="right-info-content">
         <div class="right-block block1">
-          <div class="info-value">{{fireSgWarnInfo.sgZbAlarmNum}}</div>
+          <div class="info-value">{{ fireSgWarnInfo.sgZbAlarmNum }}</div>
           <div class="info-label">指标预警</div>
         </div>
         <div class="right-block block2">
-          <div class="info-value">{{fireSgWarnInfo.yjjbLevelStr}}</div>
+          <div class="info-value">{{ fireSgWarnInfo.yjjbLevelStr }}</div>
           <div class="info-label">预警等级</div>
         </div>
         <div class="right-block block3">
-          <div class="info-value">{{fireSgWarnInfo.sgSwAlarmAddress}}</div>
+          <div class="info-value">{{ fireSgWarnInfo.sgSwAlarmAddress }}</div>
           <div class="info-label">升温预警</div>
         </div>
       </div>
     </div>
     <!-- 渲染所有模块 -->
-    <ModuleCommon 
-      v-for="cfg in cfgs" 
+    <ModuleCommon
+      v-for="cfg in cfgs"
       :key="cfg.deviceType + cfg.moduleName"
-      :show-style="cfg.showStyle" 
+      :show-style="cfg.showStyle"
       :module-data="cfg.moduleData"
-      :module-name="cfg.moduleName" 
-      :device-type="cfg.deviceType" 
-      :data="data" 
-      :visible="true" />
+      :module-name="cfg.moduleName"
+      :device-type="cfg.deviceType"
+      :data="data"
+      :visible="true"
+    />
     <ModuleCommonDual
       v-if="cfgA && cfgB"
       :show-style="cfgA.showStyle"
@@ -69,253 +70,271 @@
   </div>
 </template>
 <script lang="ts" setup>
-import { computed, onMounted, onUnmounted, ref } from 'vue';
-import { useInitConfigs, useInitPage } from './hooks/useInit';
-import { getDisHome,getDeviceSys } from './configurable.api';
-import { testConfigTSFire } from './configurable.data.tashan';
-import ModuleCommon from './components/ModuleCommon.vue';
-import ModuleCommonDual from './components/ModuleCommonDual.vue';
+  import { computed, onMounted, onUnmounted, ref } from 'vue';
+  import { useInitConfigs, useInitPage } from './hooks/useInit';
+  import { getAlarmRecord, getDeviceSys } from './configurable.api';
+  import { testConfigTSFire } from './configurable.data.tashan';
+  import ModuleCommon from './components/ModuleCommon.vue';
+  import ModuleCommonDual from './components/ModuleCommonDual.vue';
 
-const cfgs = computed(() =>
-  configs.value.filter((_, index) => index !== 6 && index !== 7 && index !== 8)
-);
-const cfgA = computed<any>(() =>
-  configs.value[6]
-);
-const cfgB = computed<any>(() =>
-  configs.value[7]
-);
-const cfgC = computed<any>(() =>
-  configs.value[8]
-);
-const { configs, devicesTypes, fetchConfigs } = useInitConfigs();
-const { mainTitle, data, updateData } = useInitPage('回采工作面智能管控');
-let interval: ReturnType<typeof setInterval> | undefined;
-const commonTitle = "实时监测与预警"
-const fireSgWarnInfo = ref ({
-  aqfxLevelStr: "-",
-  nyAlarmLevel: 0,
-  nyAlarmLevelStr: "-",
-  sgCoTbAlarmAddress: "-",
-  sgMaxTemp: '-',
-  sgSwAlarmAddress: "-",
-  sgZbAlarmNum: 0,
-  yjjbLevelStr: "-"
-});
-onMounted(() => {
-  fetchConfigs('ts_fire').then(() => {
-    configs.value = testConfigTSFire;
-    getDeviceSys({
-      devicetype: 'sys',
-      systemID: '1955807282207465474',
-      type: 'all'
-    }).then((res)=>{
-      const processedRes = handleData(res);
-      updateData(processedRes)
-    });;
+  const cfgs = computed(() => configs.value.filter((_, index) => index !== 6 && index !== 7 && index !== 8));
+  const cfgA = computed<any>(() => configs.value[6]);
+  const cfgB = computed<any>(() => configs.value[7]);
+  const cfgC = computed<any>(() => configs.value[8]);
+  const { configs, fetchConfigs } = useInitConfigs();
+  const { mainTitle, data, updateData } = useInitPage('回采工作面智能管控');
+  let interval: ReturnType<typeof setInterval> | undefined;
+  const commonTitle = '实时监测与预警';
+  const fireSgWarnInfo = ref({
+    aqfxLevelStr: '-',
+    nyAlarmLevel: 0,
+    nyAlarmLevelStr: '-',
+    sgCoTbAlarmAddress: '-',
+    sgMaxTemp: '-',
+    sgSwAlarmAddress: '-',
+    sgZbAlarmNum: 0,
+    yjjbLevelStr: '-',
   });
-  interval = setInterval(() => {
-    getDeviceSys({
-      devicetype: 'sys',
-      systemID: '1955807282207465474',
-      type: 'all'
-    }).then((res)=>{
-      const processedRes = handleData(res);
-      updateData(processedRes)
+  onMounted(() => {
+    let alarmLogData = [];
+    fetchConfigs('ts_fire').then(() => {
+      configs.value = testConfigTSFire;
+      getDeviceSys({
+        devicetype: 'sys',
+        type: 'all',
+      }).then((res) => {
+        const processedRes = handleData(res);
+        getAlarmRecord({
+          sysId: '1955807282207465474',
+          devicekind: 'bundletube',
+          pageNo: '1',
+          pageSize: '10',
+        }).then((res) => {
+          alarmLogData = res.records || [];
+          processedRes.alarmLog = alarmLogData;
+          updateData(processedRes);
+        });
+      });
     });
-  }, 2000);
-});
+    interval = setInterval(() => {
+      getDeviceSys({
+        devicetype: 'sys',
+        type: 'all',
+      }).then((res) => {
+        const processedRes = handleData(res);
+        processedRes.alarmLog = alarmLogData;
+        updateData(processedRes);
+      });
+    }, 2000);
+  });
 
-const handleData = (res: any) => {
-  const processedData = { ...res };
-  fireSgWarnInfo.value = res?.fireSgWarnInfo || {};;
-  processedData.sysInfo.coalSpoCha = JSON.parse(`${res.sysInfo.coalSpoCha}` || '[]');
-  return processedData;
-};
+  const handleData = (res: any) => {
+    const processedData = { ...res };
+    fireSgWarnInfo.value = res?.fireSgWarnInfo || {};
+    // 处理束管数据,分类进风、回风
+    if (processedData.deviceInfo?.bundletube) {
+      const { datalist = [] } = processedData.deviceInfo.bundletube;
+      processedData.deviceInfo.bundletube = {
+        ...processedData.deviceInfo.bundletube,
+        enterWind: datalist.filter((item) => item.strRemark === 'enterWind'),
+        returnWind: datalist.filter((item) => item.strRemark === 'returnWind'),
+      };
+    }
+    // 处理开采煤层自燃发火特性
+    // if (processedData.sysInfo.coalSpoCha && typeof processedData.sysInfo.coalSpoCha === 'string') {
+    //   processedData.sysInfo.coalSpoCha = JSON.parse(res.sysInfo.coalSpoCha || '[]');
+    // }
+    // 处理光纤测温数据
+    // if (processedData.deviceInfo?.fiber?.datalist) {
+    //   processedData.deviceInfo.fiber.datalist.forEach((item) => {
+    //     item.readData.fibreTemperature = JSON.parse(item.readData.fibreTemperature || '[]');
+    //   });
+    // }
+    return processedData;
+  };
 
-onUnmounted(() => {
-  clearInterval(interval);
-});
+  onUnmounted(() => {
+    clearInterval(interval);
+  });
 </script>
 <style lang="less" scoped>
-@import '/@/design/theme.less';
-
-@font-face {
-  font-family: 'douyuFont';
-  src: url('../../../../assets/font/douyuFont.otf');
-}
+  @import '/@/design/theme.less';
 
-.company-home {
-  --image-fire-title: url(/@/assets/images/vent/vent-header1.png);
-  --image-common-border1: url('/@/assets/images/home-container/configurable/minehome/common-border1.png');
-  --image-common-border3: url('/@/assets/images/home-container/configurable/minehome/common-border3.png');
-  width: 100%;
-  height: 100%;
-  color: @white;
-  position: relative;
-  background: #09172c;
+  @font-face {
+    font-family: 'douyuFont';
+    src: url('../../../../assets/font/douyuFont.otf');
+  }
 
-  .top-bg {
+  .company-home {
+    --image-fire-title: url(/@/assets/images/vent/vent-header1.png);
+    --image-common-border1: url('/@/assets/images/home-container/configurable/minehome/common-border1.png');
+    --image-common-border3: url('/@/assets/images/home-container/configurable/minehome/common-border3.png');
     width: 100%;
-    height: 73px;
-    background: var(--image-fire-title) no-repeat top;
-    position: absolute;
-    z-index: 1;
-    .main-title {
-      height: 80px;
-      font-family: 'douyuFont';
-      font-size: 26px;
-      letter-spacing: 2px;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      padding: 0 0 10px 0;
-    }
-  }
-  // 顶部中间样式块
-  .center-info-bar {
+    height: 100%;
+    color: @white;
     position: relative;
-    top: 75px;
-    left: 50%;
-    transform: translateX(-50%);
-    width: 900px;
-    height: 160px;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    background: url('@/assets/images/home-container/configurable/tashanhome/center-bar-bg.png') no-repeat center;
+    background: #09172c;
 
-    .center-info-content {
-      position: relative;
-      top: 15px;
-      background: url('@/assets/images/home-container/configurable/tashanhome/center-bar-circle.png') no-repeat center;
-      width: 160px;
-      height: 160px;
-      text-align: center;
-      .info-value {
-        position: absolute;
-        top: 34%;
-        left: 50%;
-        transform: translateX(-50%);
+    .top-bg {
+      width: 100%;
+      height: 73px;
+      background: var(--image-fire-title) no-repeat top;
+      position: absolute;
+      z-index: 1;
+      .main-title {
+        height: 80px;
         font-family: 'douyuFont';
-        font-size: 25px;
-        color: #2cffdd;
-      }
-      .info-label {
-        width: 100%;
-        position: absolute;
-        bottom: 25px;
-        font-size: 17px;
-        left: 50%;
-        transform: translateX(-50%);
+        font-size: 26px;
+        letter-spacing: 2px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 0 10px 0;
       }
     }
-    .left-info-content {
+    // 顶部中间样式块
+    .center-info-bar {
       position: relative;
-      text-align: right;
-      .left-block {
-        position: absolute;
-        width: 190px;
-        height: 55px;
-        background: url('@/assets/images/home-container/configurable/tashanhome/leftbar-bg1.png') no-repeat right;
-        padding-right: 52px;
+      top: 75px;
+      left: 50%;
+      transform: translateX(-50%);
+      width: 900px;
+      height: 160px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background: url('@/assets/images/home-container/configurable/tashanhome/center-bar-bg.png') no-repeat center;
+
+      .center-info-content {
+        position: relative;
+        top: 15px;
+        background: url('@/assets/images/home-container/configurable/tashanhome/center-bar-circle.png') no-repeat center;
+        width: 160px;
+        height: 160px;
+        text-align: center;
         .info-value {
-          height: 28px;
-          line-height: 28px;
+          position: absolute;
+          top: 34%;
+          left: 50%;
+          transform: translateX(-50%);
           font-family: 'douyuFont';
-          font-size: 12px;
-          color: var(--vent-gas-primary-text);
+          font-size: 25px;
+          color: #2cffdd;
         }
         .info-label {
-          height: 28px;
-          line-height: 28px;
+          width: 100%;
+          position: absolute;
+          bottom: 25px;
+          font-size: 17px;
+          left: 50%;
+          transform: translateX(-50%);
         }
       }
-      .block1 {
-        top: -70px;
-        right: -5px;
-      }
-      .block2 {
-        top: -15px;
-        left: -280px;
-        background: url('@/assets/images/home-container/configurable/tashanhome/leftbar-bg2.png') no-repeat right;
-        .info-value {
-          color: #2cffdd;
+      .left-info-content {
+        position: relative;
+        text-align: right;
+        .left-block {
+          position: absolute;
+          width: 190px;
+          height: 55px;
+          background: url('@/assets/images/home-container/configurable/tashanhome/leftbar-bg1.png') no-repeat right;
+          padding-right: 52px;
+          .info-value {
+            height: 28px;
+            line-height: 28px;
+            font-family: 'douyuFont';
+            font-size: 12px;
+            color: var(--vent-gas-primary-text);
+          }
+          .info-label {
+            height: 28px;
+            line-height: 28px;
+          }
         }
-      }
-      .block3 {
-        top: 40px;
-        right: -5px;
-      }
-    }
-    .right-info-content {
-      position: relative;
-      .right-block {
-        position: absolute;
-        width: 190px;
-        height: 55px;
-        background: url('@/assets/images/home-container/configurable/tashanhome/rightbar-bg1.png') no-repeat left;
-        padding-left: 52px;
-        .info-value {
-          height: 28px;
-          line-height: 28px;
-          font-family: 'douyuFont';
-          font-size: 12px;
-          color: var(--vent-gas-primary-text);
+        .block1 {
+          top: -70px;
+          right: -5px;
         }
-        .info-label {
-          height: 28px;
-          line-height: 28px;
+        .block2 {
+          top: -15px;
+          left: -280px;
+          background: url('@/assets/images/home-container/configurable/tashanhome/leftbar-bg2.png') no-repeat right;
+          .info-value {
+            color: #2cffdd;
+          }
         }
-      }
-      .block1 {
-        top: -70px;
-        left: -5px;
-      }
-      .block2 {
-        top: -15px;
-        right: -280px;
-        background: url('@/assets/images/home-container/configurable/tashanhome/rightbar-bg2.png') no-repeat left;
-        .info-value {
-          color: #2cffdd;
+        .block3 {
+          top: 40px;
+          right: -5px;
         }
       }
-      .block3 {
-        top: 40px;
-        left: -5px;
+      .right-info-content {
+        position: relative;
+        .right-block {
+          position: absolute;
+          width: 190px;
+          height: 55px;
+          background: url('@/assets/images/home-container/configurable/tashanhome/rightbar-bg1.png') no-repeat left;
+          padding-left: 52px;
+          .info-value {
+            height: 28px;
+            line-height: 28px;
+            font-family: 'douyuFont';
+            font-size: 12px;
+            color: var(--vent-gas-primary-text);
+          }
+          .info-label {
+            height: 28px;
+            line-height: 28px;
+          }
+        }
+        .block1 {
+          top: -70px;
+          left: -5px;
+        }
+        .block2 {
+          top: -15px;
+          right: -280px;
+          background: url('@/assets/images/home-container/configurable/tashanhome/rightbar-bg2.png') no-repeat left;
+          .info-value {
+            color: #2cffdd;
+          }
+        }
+        .block3 {
+          top: 40px;
+          left: -5px;
+        }
       }
     }
-  }
 
-  ::v-deep .dane-bd {
-    background-repeat: no-repeat;
-    background-position: center;
-    background-size: 100% 100%;
-    &.dane-w {
-      background-image: var(--image-common-border3);
-    }
-    .dane-title {
-      justify-content: space-around;
-      padding: 0 50px 0 0;
+    ::v-deep .dane-bd {
+      background-repeat: no-repeat;
+      background-position: center;
+      background-size: 100% 100%;
+      &.dane-w {
+        background-image: var(--image-common-border3);
+      }
+      .dane-title {
+        justify-content: space-around;
+        padding: 0 50px 0 0;
 
-      .common-navL {
-        font-size: 14px;
-        font-weight: bold;
-        font-family: 'douyuFont';
+        .common-navL {
+          font-size: 14px;
+          font-weight: bold;
+          font-family: 'douyuFont';
+        }
+      }
+      .dane-content {
+        border: none;
+        background: none;
+        padding: 10px 35px;
       }
     }
-    .dane-content {
-      border: none;
-      background: none;
-      padding: 10px 35px;
+    ::v-deep .table__content .table__content_list {
+      width: 95%;
+    }
+    ::v-deep .table__content .table__content_label {
+      width: 95%;
     }
-
-  }
-  ::v-deep .table__content .table__content_list {
-    width: 95%;  
-  }
-  ::v-deep .table__content .table__content_label {
-    width: 95%;
   }
-}
 </style>

+ 1 - 1
src/views/vent/home/configurable/hooks/helper.ts

@@ -40,7 +40,7 @@ export function getRawProp(formatter: string): string {
 // 获取模块所依赖的数据的方法
 export function getData(raw, readFrom, parser?) {
   const result = readFrom ? get(raw, readFrom) : raw;
-
+  if (!result) return result;
   switch (parser) {
     case 'json':
       return JSON.parse(result);

+ 3 - 1
src/views/vent/monitorManager/alarmMonitor/warn/fireWarn.vue

@@ -90,7 +90,8 @@ function getBack() {
 async function getMenuList() {
   let res = await sysTypeWarnList({ type: 'fire' });
   if (res.length != 0) {
-    menuList1.external = res.external.filter((v) => v.strtype != 'sys_surface_caimei');
+     menuList1.external = res.external
+    // menuList1.external = res.external.filter((v) => v.strtype != 'sys_surface_caimei');
     menuList1.internal = res.internal;
     menuList1.info = res.info;
     if (!activeIndex.value && menuList1.internal && menuList1.internal.length > 0) {
@@ -152,6 +153,7 @@ function getDetailList(param) {
 //内外因火灾、预警指标选项切换
 function fireMenuToggle(ind) {
   activeIndex.value = ind;
+   menuList.value=[]
   switch (ind) {
     case 0:
       loading.value = true;

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

@@ -1054,7 +1054,6 @@ let chartsColumnsFan1 = [],
 
 // 这里需要处理主备echartColumns
 if (chartsColumns.length > 0) {
-  console.log(chartsColumns);
   for (let i = 0; i < chartsColumns.length; i++) {
     let itemColumn = chartsColumns[i];
     let dataIndexFan1, dataIndexFan2;
@@ -1062,8 +1061,8 @@ if (chartsColumns.length > 0) {
       const dataIndex = itemColumn['dataIndex'] as string;
       dataIndexFan1 = dataIndex.startsWith('Fan') ? dataIndex.replace('Fan', 'Fan1') : dataIndex.replace('fan', 'fan1');
       dataIndexFan2 = dataIndex.startsWith('Fan') ? dataIndex.replace('Fan', 'Fan2') : dataIndex.replace('fan', 'fan2');
-      chartsColumnsFan1.push({ ...itemColumn, dataIndex: dataIndexFan1, legend: fanTitles[0] + itemColumn['legend'] });
-      chartsColumnsFan2.push({ ...itemColumn, dataIndex: dataIndexFan2, legend: fanTitles[1] + itemColumn['legend'] });
+      chartsColumnsFan1.push({ ...itemColumn, dataIndex: dataIndexFan1, legend: fanTitles[0] + itemColumn['des'] });
+      chartsColumnsFan2.push({ ...itemColumn, dataIndex: dataIndexFan2, legend: fanTitles[1] + itemColumn['des'] });
     }
   }
 }

+ 291 - 0
src/views/vent/monitorManager/gateMonitor/gate.threejs.one.sp.ts

@@ -0,0 +1,291 @@
+import * as THREE from 'three';
+import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
+import { getTextCanvas, renderVideo } from '/@/utils/threejs/util';
+import { drawHot } from '/@/utils/threejs/util';
+import { useAppStore } from '/@/store/modules/app';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class FmSp1 {
+  modelName = 'fmSp1';
+  model; //
+  group;
+  isLRAnimation = true; // 是否开启左右摇摆动画
+  direction = 1; // 摇摆方向
+  animationTimer: NodeJS.Timeout | null = null; // 摇摆开启定时器
+  player1;
+  player2;
+  deviceDetailCSS3D;
+  playerStartClickTime1 = new Date().getTime();
+  playerStartClickTime2 = new Date().getTime();
+
+  fmClock = new THREE.Clock();
+  mixers: THREE.AnimationMixer | undefined;
+  appStore = useAppStore();
+
+  backDamperOpenMesh;
+  backDamperClosedMesh;
+  frontDamperOpenMesh;
+  frontDamperClosedMesh;
+
+  clipActionArr = {
+    frontDoor: null as unknown as THREE.AnimationAction,
+    backDoor: null as unknown as THREE.AnimationAction,
+  };
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
+    directionalLight.position.set(344, 690, 344);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    const pointLight2 = new THREE.PointLight(0xffeeee, 1, 300);
+    pointLight2.position.set(-4, 10, 1.8);
+    pointLight2.shadow.bias = 0.05;
+    this.group?.add(pointLight2);
+
+    const pointLight3 = new THREE.PointLight(0xffeeee, 1, 200);
+    pointLight3.position.set(-0.5, -0.5, 0.75);
+    pointLight3.shadow.bias = 0.05;
+    this.group?.add(pointLight3);
+  }
+  // 重置摄像头
+  resetCamera() {
+    this.model.camera.far = 274;
+    this.model.orbitControls?.update();
+    this.model.camera.updateProjectionMatrix();
+  }
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-20, 20, 9);
+  }
+
+  /* 添加监控数据 */
+  addMonitorText(selectData) {
+    if (!this.group) {
+      return;
+    }
+    const screenDownText = VENT_PARAM['modalText']
+      ? VENT_PARAM['modalText']
+      : History_Type['type'] == 'remote'
+      ? `国能神东煤炭集团监制`
+      : '煤炭科学技术研究院有限公司研制';
+
+    const screenDownTextX = 90 - (screenDownText.length - 11) * 6;
+    const textArr = [
+      {
+        text: `远程控制自动风门`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 120,
+        y: 100,
+      },
+      {
+        text: `净通行高度(m):`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 0,
+        y: 155,
+      },
+      {
+        text: `${selectData.fclearheight ? selectData.fclearheight : '-'}`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 330,
+        y: 155,
+      },
+      {
+        text: `净通行宽度(m): `,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 0,
+        y: 215,
+      },
+      {
+        text: ` ${selectData.fclearwidth ? selectData.fclearwidth : '-'}`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 320,
+        y: 215,
+      },
+      {
+        text: `故障诊断:`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 0,
+        y: 275,
+      },
+      {
+        text: `${selectData.warnLevel_str ? selectData.warnLevel_str : '-'}`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 320,
+        y: 275,
+      },
+      {
+        text: screenDownText,
+        font: 'normal 28px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: screenDownTextX,
+        y: 325,
+      },
+    ];
+
+    //
+    getTextCanvas(526, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
+      const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+      textMap.colorSpace = THREE.SRGBColorSpace;
+      const textMaterial = new THREE.MeshBasicMaterial({
+        // 关于材质并未讲解 实操即可熟悉                 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
+        map: textMap, // 设置纹理贴图
+        transparent: true,
+        side: THREE.FrontSide, // 这里是双面渲染的意思
+      });
+      textMaterial.blending = THREE.CustomBlending;
+      const monitorPlane = this.group.getObjectByName('monitorText');
+      if (monitorPlane) {
+        monitorPlane.material = textMaterial;
+      } else {
+        const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry
+        const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
+        planeMesh.name = 'monitorText';
+        planeMesh.scale.set(0.002, 0.002, 0.002);
+        planeMesh.position.set(3.995, 0.67, -0.27);
+        this.group.add(planeMesh);
+      }
+      textMap.dispose();
+    });
+  }
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(2);
+    }
+  }
+
+  mouseUpModel() {}
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    debugger;
+    const fmSp1 = this.group.getObjectByName('FengMen_SiShanLing').getObjectByName('men1');
+    const tracks = this.group.animations[0].tracks;
+    const fontTracks: any[] = [];
+    for (let i = 0; i < tracks.length; i++) {
+      const track = tracks[i];
+      fontTracks.push(track);
+    }
+
+    this.mixers = new THREE.AnimationMixer(fmSp1);
+
+    const frontDoor = new THREE.AnimationClip('frontDoor', 22, fontTracks);
+    const frontClipAction = this.mixers.clipAction(frontDoor, fmSp1);
+    frontClipAction.clampWhenFinished = true;
+    frontClipAction.loop = THREE.LoopOnce;
+    this.clipActionArr.frontDoor = frontClipAction;
+  }
+
+  // 播放动画
+  play(handlerState, timeScale = 0.05) {
+    if (this.clipActionArr.frontDoor) {
+      let handler = () => {};
+      switch (handlerState) {
+        case 1: // 打开前门
+          handler = () => {
+            this.clipActionArr.frontDoor.paused = true;
+            this.clipActionArr.frontDoor.reset();
+            this.clipActionArr.frontDoor.time = 0;
+            this.clipActionArr.frontDoor.timeScale = timeScale;
+            // this.clipActionArr.frontDoor.clampWhenFinished = true;
+            this.clipActionArr.frontDoor.play();
+            this.fmClock.start();
+
+            // 显示打开前门文字
+            if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = true;
+            if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = false;
+          };
+          break;
+        case 2: // 关闭前门
+          handler = () => {
+            this.clipActionArr.frontDoor.paused = true;
+            this.clipActionArr.frontDoor.reset(); //
+            this.clipActionArr.frontDoor.time = 1.5;
+            this.clipActionArr.frontDoor.timeScale = -timeScale;
+            // this.clipActionArr.frontDoor.clampWhenFinished = true;
+            this.clipActionArr.frontDoor.play();
+            this.fmClock.start();
+
+            if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = false;
+            if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = true;
+          };
+          break;
+        default:
+      }
+
+      handler();
+    }
+  }
+
+  mountedThree(playerDom) {
+    this.group = new THREE.Object3D();
+    this.group.name = this.modelName;
+
+    return new Promise((resolve) => {
+      if (!this.model) {
+        resolve(null);
+      }
+      this.model.setGLTFModel('fmSp1').then((gltf) => {
+        this.group = gltf[0];
+        this.group.name = 'fmSp1';
+        console.log('fmSp1', this.group);
+        this.setModalPosition();
+        this.initAnimation();
+        this.addLight();
+        this.model.animate();
+        resolve(this.model);
+      });
+    });
+  }
+
+  destroy() {
+    if (this.model) {
+      if (this.mixers) {
+        this.mixers.uncacheClip(this.clipActionArr.frontDoor.getClip());
+        this.mixers.uncacheClip(this.clipActionArr.backDoor.getClip());
+        this.mixers.uncacheAction(this.clipActionArr.frontDoor.getClip(), this.group);
+        this.mixers.uncacheAction(this.clipActionArr.backDoor.getClip(), this.group);
+        this.mixers.uncacheRoot(this.group);
+
+        if (this.model.animations[0]) this.model.animations[0].tracks = [];
+      }
+      this.model.clearGroup(this.group);
+      this.clipActionArr.backDoor = undefined;
+      this.clipActionArr.frontDoor = undefined;
+
+      this.mixers = undefined;
+
+      // document.getElementById('damper3D').parentElement.remove(document.getElementById('damper3D'))
+    }
+  }
+}
+export default FmSp1;

+ 45 - 0
src/views/vent/monitorManager/gateMonitor/gate.threejs.ts

@@ -12,6 +12,7 @@ import FmDcZHQ from './gate.threejs.window.zhq';
 import FmHsw3 from './gate.threejs.three.hsw';
 import FmYjXr from './gate.threejs.two.yj'; // 窑街行人
 import FmYj from './gate.threejs.yj'; // 窑街
+import FmSp1 from './gate.threejs.one.sp';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
 import { getDictItemsByCode } from '/@/utils/dict';
@@ -31,6 +32,7 @@ let model,
   fmHsw3, // 海石湾拱形三道风门
   fmYjXr, // 窑街拱形行人风门
   fmYj, // 窑街拱形行车风门
+  fmSp1, // 沙坪一道风门
   group: THREE.Object3D,
   fmType = '',
   windowType = 'singleWindow';
@@ -79,6 +81,8 @@ const startAnimation = () => {
       fmYjXr.mouseUpModel();
     } else if (fmType === 'fmYj') {
       fmYj.mouseUpModel();
+    } else if (fmType === 'fmSp1') {
+      fmSp1.mouseUpModel();
     }
   });
 };
@@ -111,6 +115,8 @@ const mouseEvent = (event) => {
         fmYjXr.mousedownModel(intersects);
       } else if (fmType === 'fmYj' && fmYj) {
         fmYj.mousedownModel(intersects);
+      } else if (fmType === 'fmSp1') {
+        fmSp1.mousedownModel(intersects);
       }
     });
     console.log('摄像头控制信息', model.orbitControls, model.camera);
@@ -142,6 +148,8 @@ export const addMonitorText = (selectData) => {
     fmYjXr.addMonitorText(selectData);
   } else if (fmType === 'fmYj' && fmYj) {
     fmYj.addMonitorText(selectData);
+  } else if (fmType === 'fmSp1' && fmSp1) {
+    fmSp1.addMonitorText(selectData);
   }
 };
 
@@ -182,6 +190,8 @@ export const play = (handlerState, flag?) => {
     return fmYjXr?.play.call(fmYjXr, handlerState, flag);
   } else if (fmType === 'fmYj') {
     return fmYj?.play.call(fmYj, handlerState, flag);
+  } else if (fmType === 'fmSp1') {
+    return fmSp1?.play(handlerState, flag);
   }
 };
 
@@ -637,6 +647,34 @@ export const setModelType = (type) => {
           0.8
         );
       }, 300);
+    } else if (fmType === 'fmSp1' && fmSp1 && fmSp1.group) {
+      if (fmSp1.clipActionArr.frontDoor) {
+        fmSp1.clipActionArr.frontDoor.reset();
+        fmSp1.clipActionArr.frontDoor.time = 0.5;
+        fmSp1.clipActionArr.frontDoor.stop();
+      }
+
+      if (fmSp1.frontDamperOpenMesh) fmSp1.frontDamperOpenMesh.visible = false;
+      if (fmSp1.frontDamperClosedMesh) fmSp1.frontDamperClosedMesh.visible = true;
+
+      model.startAnimation = fmSp1.render.bind(fmSp1);
+      model.scene.remove(group);
+      group = fmSp1.group;
+      group.rotation.y = 0;
+
+      const oldCameraPosition = { x: -1000, y: 100, z: 500 };
+      setTimeout(async () => {
+        resolve(null);
+        model.scene.add(fmSp1.group);
+        await animateCamera(
+          oldCameraPosition,
+          { x: 0, y: 0, z: 0 },
+          { x: 50.99, y: 69.32, z: 93.61 },
+          { x: -10.04, y: -14.38, z: -31.4 },
+          model,
+          0.8
+        );
+      }, 300);
     }
   });
 };
@@ -715,6 +753,11 @@ export const mountedThree = (playerDom) => {
             fmYj = new FmYj(model);
             await fmYj.mountedThree();
             break;
+          case 'fmSp1':
+            debugger;
+            fmSp1 = new FmSp1(model);
+            await fmSp1.mountedThree();
+            break;
         }
       }
       resolve(null);
@@ -756,6 +799,7 @@ export const destroy = () => {
     if (fmHsw3) fmHsw3.destroy();
     if (fmYjXr) fmYjXr.destroy();
     if (fmYj) fmYj.destroy();
+    if (fmSp1) fmSp1.destroy();
     fm1 = null;
     fm2 = null;
     fm3 = null;
@@ -768,6 +812,7 @@ export const destroy = () => {
     fmHsw3 = null;
     fmYjXr = null;
     fmYj = null;
+    fmSp1 = null;
     group = null;
     model.mixers = [];
     model.destroy();

+ 800 - 766
src/views/vent/monitorManager/gateMonitor/index.vue

@@ -27,12 +27,34 @@
         <div v-if="hasPermission('btn:control')" class="button-box" @click="playAnimation(2)">关闭前门</div>
         <div v-if="hasPermission('btn:control') && selectData.ndoorcount == '3'" class="button-box" @click="playAnimation(8)">打开中间门</div>
         <div v-if="hasPermission('btn:control') && selectData.ndoorcount == '3'" class="button-box" @click="playAnimation(9)">关闭中间门</div>
-        <div v-if="hasPermission('btn:control')" class="button-box" @click="playAnimation(3)">打开后门</div>
-        <div v-if="hasPermission('btn:control')" class="button-box" @click="playAnimation(4)">关闭后门</div>
-        <div v-if="hasPermission('btn:totalControl') || selectData['isShowGatesContrl'] == 1" class="button-box" @click="playAnimation(5)"
+        <div
+          v-if="hasPermission('btn:control') && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3')"
+          class="button-box"
+          @click="playAnimation(3)"
+          >打开后门</div
+        >
+        <div
+          v-if="hasPermission('btn:control') && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3')"
+          class="button-box"
+          @click="playAnimation(4)"
+          >关闭后门</div
+        >
+        <div
+          v-if="
+            hasPermission('btn:totalControl') ||
+            (selectData['isShowGatesContrl'] == 1 && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3'))
+          "
+          class="button-box"
+          @click="playAnimation(5)"
           >同时打开</div
         >
-        <div v-if="hasPermission('btn:totalControl') || selectData['isShowGatesContrl'] == 1" class="button-box" @click="playAnimation(6)"
+        <div
+          v-if="
+            hasPermission('btn:totalControl') ||
+            (selectData['isShowGatesContrl'] == 1 && (selectData.ndoorcount == '2' || selectData.ndoorcount == '3'))
+          "
+          class="button-box"
+          @click="playAnimation(6)"
           >同时关闭</div
         >
         <template v-if="selectData['gateStyle'] && selectData['gateStyle'].includes('fm_fc')">
@@ -340,848 +362,860 @@
 </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 { 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');
+  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 { 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 { 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 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 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 { 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']]);
+  // 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;
+            }
+            getMonitor();
           }
-          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
-    );
+        },
+        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':
+    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;
+        default:
+          type = gateStyle;
+      }
+    } 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';
+        } 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 'fmYy':
-        type = 'fm1';
+      case 2: // 关闭前门
+        if (selectData.frontGateOpen == '1' && selectData.frontGateClose == '0') {
+          modalTitle.value = '关闭前门';
+          modalType.value = '2';
+          modalIsShow.value = true;
+        } else {
+          // message.warning('前门已经关闭或正在关闭,请勿重新操作');
+          message.warning('没有监测到前门开到位,无法进行指令下发操作');
+        }
         break;
-      case 'fmSs3':
-        type = 'fm2';
+      case 3: // 打开后门
+        if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
+          modalTitle.value = '打开后门';
+          modalType.value = '3';
+          modalIsShow.value = true;
+        } else {
+          // message.warning('后门已经打开或正在打开,请勿重新操作');
+          message.warning('没有监测到后门关到位,无法进行指令下发操作');
+        }
         break;
-      case 'fm_fc_hjg':
-        type = 'fmWindowHjg';
+      case 4: // 关闭后门
+        if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
+          modalTitle.value = '关闭后门';
+          modalType.value = '4';
+          modalIsShow.value = true;
+        } else {
+          // message.warning('后门已经关闭或正在关闭,请勿重新操作');
+          message.warning('没有监测到后门开到位,无法进行指令下发操作');
+        }
         break;
-      case 'fm_fc_zhq':
-        type = 'fmWindowZhq';
+      case 8: // 打开中间门
+        if (selectData.midGateOpen == '0' && selectData.midGateClose == '1') {
+          modalTitle.value = '打开中间门';
+          modalType.value = '8';
+          modalIsShow.value = true;
+        } else {
+          // message.warning('后门已经打开或正在打开,请勿重新操作');
+          message.warning('没有监测到中间门关到位,无法进行指令下发操作');
+        }
         break;
-      case 'fmHsw3':
-        type = 'fmHsw3';
+      case 9: // 关闭中间门
+        if (selectData.midGateOpen == '1' && selectData.midGateClose == '0') {
+          modalTitle.value = '关闭中间门';
+          modalType.value = '9';
+          modalIsShow.value = true;
+        } else {
+          // message.warning('后门已经关闭或正在关闭,请勿重新操作');
+          message.warning('没有监测到中间门开到位,无法进行指令下发操作');
+        }
         break;
-      case 'fmYjXr':
-        type = 'fmYjXr';
+      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 'fmYj':
-        type = 'fmYj';
+      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;
-    }
-  } 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);
-}
 
-// 播放动画
-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('没有监测到前门开到位,无法进行指令下发操作');
-      }
-      break;
-    case 3: // 打开后门
-      if (selectData.rearGateOpen == '0' && selectData.rearGateClose == '1') {
-        modalTitle.value = '打开后门';
-        modalType.value = '3';
-        modalIsShow.value = true;
-      } else {
-        // message.warning('后门已经打开或正在打开,请勿重新操作');
-        message.warning('没有监测到后门关到位,无法进行指令下发操作');
-      }
-      break;
-    case 4: // 关闭后门
-      if (selectData.rearGateOpen == '1' && selectData.rearGateClose == '0') {
-        modalTitle.value = '关闭后门';
-        modalType.value = '4';
+      case 7: // 控制模式切换
+        modalTitle.value = '控制模式切换';
+        modalType.value = '7';
         modalIsShow.value = true;
-      } else {
-        // message.warning('后门已经关闭或正在关闭,请勿重新操作');
-        message.warning('没有监测到后门开到位,无法进行指令下发操作');
-      }
-      break;
-    case 8: // 打开中间门
-      if (selectData.midGateOpen == '0' && selectData.midGateClose == '1') {
-        modalTitle.value = '打开中间门';
-        modalType.value = '8';
+        break;
+
+      case 10: // 风窗控制
+        modalTitle.value = 'A窗控制';
+        modalType.value = '10';
         modalIsShow.value = true;
-      } else {
-        // message.warning('后门已经打开或正在打开,请勿重新操作');
-        message.warning('没有监测到中间门关到位,无法进行指令下发操作');
-      }
-      break;
-    case 9: // 关闭中间门
-      if (selectData.midGateOpen == '1' && selectData.midGateClose == '0') {
-        modalTitle.value = '关闭中间门';
-        modalType.value = '9';
+        break;
+
+      case 11: // 风窗控制
+        modalTitle.value = 'B窗控制';
+        modalType.value = '11';
         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';
+        break;
+      case 12: // 风窗控制
+        modalTitle.value = 'C窗控制';
+        modalType.value = '12';
         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';
+        break;
+      case 13: // 风窗控制
+        modalTitle.value = 'D窗控制';
+        modalType.value = '13';
         modalIsShow.value = true;
-      } else {
-        // message.warning('前后门已经关闭或正在关闭,请勿重新操作');
-        message.warning('没有监测到前门、后门开到位,无法进行指令下发操作');
-      }
-      break;
-
-    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;
-  }
+        break;
+    }
 
-  if (globalConfig?.simulatedPassword) {
-    handleOK('', handlerState + '');
+    if (globalConfig?.simulatedPassword) {
+      handleOK('', handlerState + '');
+    }
+    contrlValue = value;
   }
-  contrlValue = value;
-}
-// 保德缺打开状态
+  // 保德缺打开状态
 
-// 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;
+  // 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;
 
-//     case 7: // 控制模式切换
-//       modalTitle.value = '控制模式切换';
-//       modalType.value = '7';
-//       modalIsShow.value = true;
-//       break;
-//     case 10: // 风窗控制
-//       modalTitle.value = '风窗控制';
-//       modalType.value = '10';
-//       modalIsShow.value = true;
-//       break;
-//   }
+  //     case 7: // 控制模式切换
+  //       modalTitle.value = '控制模式切换';
+  //       modalType.value = '7';
+  //       modalIsShow.value = true;
+  //       break;
+  //     case 10: // 风窗控制
+  //       modalTitle.value = '风窗控制';
+  //       modalType.value = '10';
+  //       modalIsShow.value = true;
+  //       break;
+  //   }
 
-//   if (globalConfig?.simulatedPassword) {
-//     handleOK('', handlerState + '');
-//   }
-//   contrlValue = value;
-// }
+  //   if (globalConfig?.simulatedPassword) {
+  //     handleOK('', handlerState + '');
+  //   }
+  //   contrlValue = value;
+  // }
 
-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;
+  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';
+    switch (handlerState) {
+      case '1': // 打开前门
+        if (selectData.frontGateOpen == '0' && selectData.frontGateClose == '1') {
+          handler = () => {
+            frontDoorIsOpen.value = true;
+          };
+          data.paramcode = 'frontGateOpen_S';
         } else {
-          data.paramcode = 'autoRoManualControl0';
+          message.warning('前门已打开。。。');
+          modalIsShow.value = false;
         }
-        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;
-  }
+        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;
+        } 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('指令已下发至生产管控平台成功!');
+    if (data.paramcode) {
+      deviceControlApi(data).then((res) => {
+        // 模拟时开启
+        if (res.success) {
+          modalIsShow.value = false;
+          if (globalConfig.History_Type == 'remote') {
+            message.success('指令已下发至生产管控平台成功!');
+          } else {
+            message.success('指令已下发成功!');
+          }
         } else {
-          message.success('指令已下发成功!');
+          message.error(res.message);
         }
-      } 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('指令已下发成功!');
+  //     }
+  //   });
+  // }
 
-// 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 () => {
+  // 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;
-          dataSource.value = [];
-          addMonitorText(selectData);
-        });
-      }
-    })
-    .catch(() => {
-      debugger;
-    });
-});
+        } else {
+          // 韩咀无风门设备,只有报警历史数据,无其他数据
+          setModelType('fm1').then(async () => {
+            loading.value = false;
+            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;
+  .button-box {
+    border: none !important;
+    height: 34px !important;
 
-  &:hover {
-    background: var(--vent-device-manager-control-btn-hover) !important;
-  }
+    &:hover {
+      background: var(--vent-device-manager-control-btn-hover) !important;
+    }
 
-  &::before {
-    height: 27px !important;
-    background: var(--vent-device-manager-control-btn) !important;
-  }
+    &::before {
+      height: 27px !important;
+      background: var(--vent-device-manager-control-btn) !important;
+    }
 
-  &::after {
-    top: 35px !important;
+    &::after {
+      top: 35px !important;
+    }
   }
-}
 
-:deep(.@{ventSpace}-tabs-tabpane-active) {
-  height: 100%;
-}
+  :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;
-}
+  ::-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>

+ 512 - 0
src/views/vent/monitorManager/windowMonitor/shuangdaoFcZhq.threejs.ts

@@ -0,0 +1,512 @@
+import * as THREE from 'three';
+import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer.js';
+import { getTextCanvas, renderVideo } from '/@/utils/threejs/util';
+import gsap from 'gsap';
+import { drawHot } from '/@/utils/threejs/util';
+import { useAppStore } from '/@/store/modules/app';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class SdFcZhq {
+  modelName = 'sdFc';
+  model; //
+  group;
+  isLRAnimation = true; // 是否开启左右摇摆动画
+  direction = 1; // 摇摆方向
+  animationTimer: NodeJS.Timeout | null = null; // 摇摆开启定时器
+  player1;
+  player2;
+  deviceDetailCSS3D;
+  playerStartClickTime1 = new Date().getTime();
+  playerStartClickTime2 = new Date().getTime();
+
+  fmClock = new THREE.Clock();
+  mixers: THREE.AnimationMixer | undefined;
+  appStore = useAppStore();
+
+  // backLeftDamperOpenMesh;
+  // backLeftDamperClosedMesh;
+  // frontLeftDamperOpenMesh;
+  // frontLeftDamperClosedMesh;
+  // backRightDamperOpenMesh;
+  // backRightDamperClosedMesh;
+  // frontRightDamperOpenMesh;
+  // frontRightDamperClosedMesh;
+
+  clipActionArr = {
+    frontDoor: null as unknown as THREE.AnimationAction,
+    backDoor: null as unknown as THREE.AnimationAction,
+  };
+  windowsActionArr = {
+    frontWindow: <THREE.Mesh[]>[],
+    backWindow: <THREE.Mesh[]>[],
+  };
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {}
+  // 重置摄像头
+  resetCamera() {
+    this.model.camera.far = 274;
+    this.model.orbitControls?.update();
+    this.model.camera.updateProjectionMatrix();
+  }
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-20, 20, 9);
+  }
+
+  /* 添加监控数据 */
+  addMonitorText(selectData) {
+    if (!this.group) {
+      return;
+    }
+    const screenDownText = VENT_PARAM['modalText']
+      ? VENT_PARAM['modalText']
+      : History_Type['type'] == 'remote'
+      ? `国能神东煤炭集团监制`
+      : '煤炭科学技术研究院有限公司研制';
+
+    const screenDownTextX = 80 - (screenDownText.length - 10) * 6;
+
+    const textArr = [
+      {
+        text: `远程控制自动风门`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 120,
+        y: 100,
+      },
+      {
+        text: `净通行高度(m):`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 0,
+        y: 155,
+      },
+      {
+        text: `${selectData.fclearheight ? selectData.fclearheight : '-'}`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 290,
+        y: 155,
+      },
+      {
+        text: `净通行宽度(m): `,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 0,
+        y: 215,
+      },
+      {
+        text: ` ${selectData.fclearwidth ? selectData.fclearwidth : '-'}`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 280,
+        y: 215,
+      },
+      {
+        text: `故障诊断:`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 0,
+        y: 275,
+      },
+      {
+        text: `${selectData.warnLevel_str ? selectData.warnLevel_str : '-'}`,
+        font: 'normal 30px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: 280,
+        y: 275,
+      },
+      {
+        text: screenDownText,
+        font: 'normal 28px Arial',
+        color: '#00FF00',
+        strokeStyle: '#007400',
+        x: screenDownTextX,
+        y: 325,
+      },
+    ];
+    //
+    getTextCanvas(526, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
+      const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+      textMap.colorSpace = THREE.SRGBColorSpace;
+      const textMaterial = new THREE.MeshBasicMaterial({
+        // 关于材质并未讲解 实操即可熟悉                 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
+        map: textMap, // 设置纹理贴图
+        transparent: true,
+        side: THREE.FrontSide, // 这里是双面渲染的意思
+      });
+      textMaterial.blending = THREE.CustomBlending;
+      const monitorPlane = this.group.getObjectByName('monitorText');
+      if (monitorPlane) {
+        monitorPlane.material = textMaterial;
+      } else {
+        const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry
+        const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
+        planeMesh.name = 'monitorText';
+        planeMesh.scale.set(0.002, 0.002, 0.002);
+        planeMesh.position.set(4.025, 0.67, -0.27);
+        this.group.add(planeMesh);
+      }
+      textMap.dispose();
+    });
+  }
+
+  /** 添加热点 */
+  drawHots() {
+    const hotPositions = [
+      { x: -0.37, y: 0.26, z: -0.32 },
+      { x: 0.28, y: -0.2, z: -0.43 },
+      { x: 0.55, y: -0.22, z: -0.38 },
+    ];
+    for (let i = 0; i < 3; i++) {
+      const hotPoint = drawHot(0.1);
+      const position = hotPositions[i];
+      hotPoint.scale.set(0.1, 0.1, 0.1);
+      hotPoint.position.set(position.x, position.y, position.z);
+      hotPoint.name = 'hotPoint' + i;
+      this.group?.add(hotPoint);
+    }
+  }
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(2);
+    }
+  }
+
+  /* 点击风窗,风窗全屏 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    if (this.animationTimer) {
+      clearTimeout(this.animationTimer);
+      this.animationTimer = null;
+    }
+  }
+
+  mouseUpModel() {}
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    const fmGroup = this.group?.getObjectByName('fm-window-zhq');
+    if (fmGroup) {
+      const tracks = fmGroup.animations[0].tracks;
+      const fontTracks: any[] = [],
+        backTracks: any[] = [];
+      for (let i = 0; i < tracks.length; i++) {
+        const track = tracks[i];
+        if (track.name.includes('_3') || track.name.includes('_4')) {
+          fontTracks.push(track);
+        } else {
+          backTracks.push(track);
+        }
+      }
+      const parentGroup = fmGroup.getObjectByName('MenChuangYiTi');
+      // const frontGroup = parentGroup.getObjectByName('FengMen2');
+      // const backGroup = parentGroup.getObjectByName('FengMen1');
+      this.mixers = new THREE.AnimationMixer(parentGroup);
+
+      const frontDoor = new THREE.AnimationClip('frontDoor', 2.5, fontTracks);
+      const frontClipAction = this.mixers.clipAction(frontDoor, parentGroup);
+      frontClipAction.clampWhenFinished = true;
+      frontClipAction.loop = THREE.LoopOnce;
+      this.clipActionArr.frontDoor = frontClipAction;
+
+      const backDoor = new THREE.AnimationClip('backDoor', 2.5, backTracks);
+      const backClipAction = this.mixers.clipAction(backDoor, parentGroup);
+      backClipAction.clampWhenFinished = true;
+      backClipAction.loop = THREE.LoopOnce;
+      this.clipActionArr.backDoor = backClipAction;
+    }
+    // 编写风窗
+  }
+  /* 提取风门序列帧,初始化前后门动画 */
+  initWindowAnimation() {
+    const meshArr01: THREE.Object3D[] = []; //front left
+    const meshArr02: THREE.Object3D[] = []; //front right
+    const windowGroup = new THREE.Group();
+    windowGroup.name = 'hiddenGroup';
+    const fmGroup = this.group?.getObjectByName('fm-window-zhq');
+    const parentGroup = fmGroup.getObjectByName('MenChuangYiTi');
+    const frontGroup = parentGroup.getObjectByName('Men_hou');
+    const backGroup = parentGroup.getObjectByName('Men_qian');
+    const frontLeftObj = frontGroup.getObjectByName('men_3');
+    const frontRightObj = frontGroup.getObjectByName('men_4');
+    const backLeftObj = backGroup.getObjectByName('men_1');
+    const backRightObj = backGroup.getObjectByName('men_2');
+    frontLeftObj.traverse((obj) => {
+      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('men')) {
+        obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+        meshArr01.push(obj);
+      }
+    });
+    frontRightObj.traverse((obj) => {
+      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('men')) {
+        obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+        meshArr01.push(obj);
+      }
+    });
+    backLeftObj.traverse((obj) => {
+      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('men')) {
+        obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+        meshArr02.push(obj);
+      }
+    });
+    backRightObj.traverse((obj) => {
+      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('men')) {
+        obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+        meshArr02.push(obj);
+      }
+    });
+
+    this.windowsActionArr.frontWindow = meshArr01;
+    this.windowsActionArr.backWindow = meshArr02;
+    this.group?.add(windowGroup);
+  }
+
+  deviceDetailCard(position = { x: 0, y: 0, z: 0 }) {
+    const element = document.getElementById('deviceCard') as HTMLElement;
+    if (element) {
+      this.deviceDetailCSS3D = new CSS2DObject(element);
+      this.deviceDetailCSS3D.name = 'deviceCard';
+      this.deviceDetailCSS3D.position.set(position.x, position.y, position.z);
+      this.deviceDetailCSS3D.visible = false;
+      // this.model.scene.add(this.deviceDetailCSS3D);
+      this.group.add(this.deviceDetailCSS3D);
+    }
+  }
+
+  // 播放动画
+  playGate(handlerState, timeScale = 0.01) {
+    let handler = () => {};
+    if (this.clipActionArr.frontDoor && this.clipActionArr.backDoor) {
+      switch (handlerState) {
+        case 1: // 打开前门
+          handler = () => {
+            this.clipActionArr.frontDoor.paused = true;
+            this.clipActionArr.frontDoor.reset();
+            this.clipActionArr.frontDoor.time = 0;
+            this.clipActionArr.frontDoor.timeScale = timeScale;
+            // this.clipActionArr.frontDoor.clampWhenFinished = true;
+            this.clipActionArr.frontDoor.play();
+            this.fmClock.start();
+
+            // 显示打开前门文字
+            if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = true;
+            if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = false;
+          };
+          break;
+        case 2: // 关闭前门
+          handler = () => {
+            this.clipActionArr.frontDoor.paused = true;
+            this.clipActionArr.frontDoor.reset(); //
+            this.clipActionArr.frontDoor.time = 2.5;
+            this.clipActionArr.frontDoor.timeScale = -timeScale;
+            // this.clipActionArr.frontDoor.clampWhenFinished = true;
+            this.clipActionArr.frontDoor.play();
+            this.fmClock.start();
+
+            if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = false;
+            if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = true;
+          };
+          break;
+        case 3: // 打开后门
+          handler = () => {
+            this.clipActionArr.backDoor.paused = true;
+            this.clipActionArr.backDoor.reset();
+            this.clipActionArr.backDoor.time = 0;
+            this.clipActionArr.backDoor.timeScale = timeScale;
+            // this.clipActionArr.backDoor.clampWhenFinished = true;
+            this.clipActionArr.backDoor.play();
+            this.fmClock.start();
+
+            if (this.backDamperOpenMesh) this.backDamperOpenMesh.visible = true;
+            if (this.backDamperClosedMesh) this.backDamperClosedMesh.visible = false;
+          };
+          break;
+        case 4: // 关闭后门
+          handler = () => {
+            this.clipActionArr.backDoor.paused = true;
+            this.clipActionArr.backDoor.reset();
+            this.clipActionArr.backDoor.time = 2.5;
+            this.clipActionArr.backDoor.timeScale = -timeScale;
+            // this.clipActionArr.backDoor.clampWhenFinished = true;
+            this.clipActionArr.backDoor.play();
+            this.fmClock.start();
+
+            if (this.backDamperOpenMesh) this.backDamperOpenMesh.visible = false;
+            if (this.backDamperClosedMesh) this.backDamperClosedMesh.visible = true;
+          };
+          break;
+        default:
+      }
+      handler();
+    }
+  }
+
+  play(rotationParam, flag) {
+    if (
+      !this.windowsActionArr.frontWindow ||
+      !this.windowsActionArr.backWindow ||
+      this.windowsActionArr.frontWindow.length <= 0 ||
+      this.windowsActionArr.backWindow.length <= 0
+    ) {
+      return;
+    }
+    if (flag === 1) {
+      // 前门左风窗动画
+      this.windowsActionArr.frontWindow.forEach((mesh) => {
+        gsap.to(mesh.rotation, {
+          y: THREE.MathUtils.degToRad(rotationParam.frontDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.frontLeftDeg1 - mesh.rotation.y),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 2) {
+      // 后门左风窗动画
+      this.windowsActionArr.backWindow.forEach((mesh) => {
+        gsap.to(mesh.rotation, {
+          y: THREE.MathUtils.degToRad(rotationParam.backDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.backLeftDeg1 - mesh.rotation.y),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 0) {
+      ([...this.windowsActionArr.frontWindow, ...this.windowsActionArr.backWindow] as THREE.Mesh[]).forEach((mesh) => {
+        gsap.to(mesh.rotation, {
+          y: 0,
+          overwrite: true,
+        });
+      });
+    }
+  }
+
+  async initCamera(dom1) {
+    const videoPlayer1 = dom1;
+    this.player1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    if (!videoPlayer1) {
+      const textArr = [
+        {
+          text: `无信号输入`,
+          font: 'normal 40px Arial',
+          color: '#009900',
+          strokeStyle: '#002200',
+          x: 170,
+          y: 40,
+        },
+      ];
+      const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+
+      let textMaterial: THREE.MeshBasicMaterial | null = null;
+      if (canvas) {
+        const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+        textMaterial = new THREE.MeshBasicMaterial({
+          map: textMap, // 设置纹理贴图
+          transparent: true,
+          side: THREE.DoubleSide, // 这里是双面渲染的意思
+        });
+        textMaterial.blending = THREE.CustomBlending;
+
+        const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+        monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+
+        textMaterial.dispose();
+        planeGeometry.dispose();
+        textMap.dispose();
+      }
+    }
+    const player1 = this.group.getObjectByName('player1');
+    if (player1) {
+      this.model.clearMesh(player1);
+      this.group.remove(player1);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      if (monitorPlane && !this.group.getObjectByName('noPlayer1')) {
+        const planeMesh = monitorPlane.clone();
+        planeMesh.name = 'noPlayer1';
+        planeMesh.scale.set(0.0085, 0.0055, 0.012);
+        planeMesh.position.set(-3.64, 0.01, -0.41);
+        this.group?.add(planeMesh.clone());
+      }
+    } else if (videoPlayer1) {
+      try {
+        const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+        if (mesh) {
+          mesh?.scale.set(-0.0275, 0.028, 1);
+          mesh?.position.set(-3.643, 0.02, -0.4);
+          mesh.rotation.y = -Math.PI;
+          this.group.add(mesh);
+        }
+      } catch (error) {
+        console.log('视频信号异常');
+      }
+    }
+  }
+
+  mountedThree() {
+    this.group = new THREE.Object3D();
+    this.group.name = this.modelName;
+    return new Promise((resolve) => {
+      this.model.setGLTFModel(['fm-window-zhq'], this.group).then(() => {
+        console.log('带风窗风门模型----->', this.group);
+        this.setModalPosition();
+        // 初始化左右摇摆动画;
+        this.initAnimation();
+        this.initWindowAnimation();
+        // this.drawHots();
+        this.addLight();
+        // this.deviceDetailCard();
+        this.model.animate();
+
+        resolve(this.model);
+      });
+    });
+  }
+
+  destroy() {
+    if (this.model) {
+      if (this.mixers) {
+        this.mixers.uncacheClip(this.clipActionArr.frontDoor.getClip());
+        this.mixers.uncacheClip(this.clipActionArr.backDoor.getClip());
+        this.mixers.uncacheAction(this.clipActionArr.frontDoor.getClip(), this.group);
+        this.mixers.uncacheAction(this.clipActionArr.backDoor.getClip(), this.group);
+        this.mixers.uncacheRoot(this.group);
+
+        if (this.model.animations[0]) this.model.animations[0].tracks = [];
+      }
+      this.model.clearGroup(this.group);
+      this.clipActionArr.backDoor = undefined;
+      this.clipActionArr.frontDoor = undefined;
+
+      this.windowsActionArr.frontWindow = undefined;
+      this.windowsActionArr.backWindow = undefined;
+
+      this.mixers = undefined;
+    }
+  }
+}
+export default SdFcZhq;

+ 22 - 0
src/views/vent/monitorManager/windowMonitor/window.threejs.ts

@@ -14,6 +14,7 @@ import ddFc_6 from './dandaoFcHjt.threejs'; // ddFc_6 单道-大窗1列扇叶(
 import ddFc_7 from './dandaoFcBd3.threejs'; // ddFc_6 单道-大窗1列扇叶(活鸡兔)
 import threeFc_8 from './sandaoFc.threejs'; // ddFc_8 三道-大窗2列门式扇叶(三道沟)
 import ddFc_lt from './dandaoFcLt.threejs';
+import SdFcZhq from './shuangdaoFcZhq.threejs';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
 import { getDictItemsByCode } from '/@/utils/dict';
@@ -37,6 +38,7 @@ let model: UseThree,
   ddFc7: ddFc_7,
   ddFc8: ddFc_lt,
   threeFc8: threeFc_8,
+  sdFcZhq: SdFcZhq,
   singleWindowXkObj: singleWindowXk,
   group: THREE.Object3D,
   windowType = 'ddFc1';
@@ -87,6 +89,8 @@ const startAnimation = () => {
       threeFc8.mouseUpModel.call(threeFc8);
     } else if (windowType === 'singleXkWindow' && singleWindowXkObj) {
       singleWindowXkObj.mouseUpModel.call(singleWindowXkObj);
+    } else if (windowType === 'sdFcZhq' && sdFcZhq) {
+      sdFcZhq.mouseUpModel();
     }
   });
 };
@@ -123,6 +127,8 @@ const mouseEvent = (event) => {
         threeFc8.mousedownModel(intersects);
       } else if (windowType === 'singleXkWindow' && singleWindowXkObj) {
         singleWindowXkObj.mousedownModel.call(singleWindowXkObj, intersects);
+      } else if (windowType === 'sdFcZhq' && sdFcZhq) {
+        sdFcZhq.mousedownModel(intersects);
       }
     });
     console.log('摄像头控制信息', model.orbitControls, model.camera);
@@ -162,6 +168,8 @@ export const addMonitorText = (selectData) => {
     return threeFc8.addMonitorText(selectData);
   } else if (windowType === 'singleXkWindow' && singleWindowXkObj) {
     return singleWindowXkObj.addMonitorText.call(singleWindowXkObj, selectData);
+  } else if (windowType === 'sdFcZhq' && sdFcZhq) {
+    sdFcZhq.addMonitorText(selectData);
   }
 };
 
@@ -282,6 +290,8 @@ export const play = (rotationParam, flag) => {
     return threeFc8.play(rotationParam, flag);
   } else if (windowType === 'singleXkWindow' && singleWindowXkObj) {
     return singleWindowXkObj.play.call(singleWindowXkObj, rotationParam, flag);
+  } else if (windowType === 'sdFcZhq' && sdFcZhq) {
+    sdFcZhq.play(rotationParam, flag);
   }
 };
 
@@ -374,6 +384,12 @@ export const setModelType = (type) => {
       newP: { x: 116.08531358656566, y: 81.45510733175816, z: 193.00752046594465 },
       newT: { x: 23.446366480086372, y: -12.335134633777185, z: -5.63294282643405 },
     },
+    sdFcZhq: {
+      render: sdFcZhq ? () => sdFcZhq.render() : null,
+      group: sdFcZhq ? sdFcZhq.group : null,
+      newP: { x: 66.257, y: 57.539, z: 94.313 },
+      newT: { x: -2.28, y: -0.91, z: -5.68 },
+    },
   };
   const oldCameraPosition = { x: 100, y: 0, z: 10 };
   model.scene?.remove(group);
@@ -464,6 +480,10 @@ export const mountedThree = () => {
           threeFc8 = new threeFc_8(model);
           await threeFc8.mountedThree();
           break;
+        case 'sdFcZhq':
+          sdFcZhq = new SdFcZhq(model);
+          await sdFcZhq.mountedThree();
+          break;
         case 'singleXkWindow':
           singleWindowXkObj = new singleWindowXk(model);
           await singleWindowXkObj.mountedThree();
@@ -493,6 +513,7 @@ export const destroy = () => {
     if (sdFc4) sdFc4.destroy();
     if (sdFc2) sdFc2.destroy();
     if (sdFc5) sdFc5.destroy();
+    if (sdFcZhq) sdFcZhq.destroy();
     if (threeFc8) threeFc8.destroy();
 
     singleWindowXkObj.destroy();
@@ -512,6 +533,7 @@ export const destroy = () => {
     sdFc4 = null;
     sdFc2 = null;
     sdFc5 = null;
+    sdFcZhq = null;
     threeFc8 = null;
   }
 };