Browse Source

解决冲突、提交新文件

hongrunxia 5 months ago
parent
commit
3ad53400e4
30 changed files with 13540 additions and 560 deletions
  1. 2 2
      public/js/config.js
  2. 11 1
      src/qiankun/index.ts
  3. 1 0
      src/utils/threejs/main.worker.ts
  4. 2 1
      src/views/vent/deviceManager/configurationTable/adapters.ts
  5. 1 3
      src/views/vent/deviceManager/configurationTable/types.ts
  6. 3 3
      src/views/vent/home/configurable/components/detail/ComplexList.vue
  7. 62 1
      src/views/vent/home/configurable/components/detail/CustomList.vue
  8. 241 108
      src/views/vent/home/configurable/configurable.data.ts
  9. 10 4
      src/views/vent/home/configurable/dustBD.vue
  10. 10 4
      src/views/vent/home/configurable/fireBD.vue
  11. 10 4
      src/views/vent/home/configurable/index.vue
  12. 95 47
      src/views/vent/monitorManager/alarmMonitor/common/closeWall.vue
  13. 387 344
      src/views/vent/monitorManager/alarmMonitor/common/fireWork.vue
  14. 12 13
      src/views/vent/monitorManager/alarmMonitor/index.vue
  15. 364 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/DetailModal.vue
  16. 943 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/conditionAssistance.vue
  17. 941 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/conditionAssistance1.vue
  18. 54 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-echart-line.vue
  19. 59 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-history.vue
  20. 36 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-operate-history.vue
  21. 29 0
      src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-warn-history.vue
  22. 65 0
      src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.api.ts
  23. 3961 0
      src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.data.ts
  24. 3961 0
      src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.data2.ts
  25. 655 0
      src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.three.ts
  26. 33 0
      src/views/vent/monitorManager/fanLocalMonitor1/fcfanLocal.three.ts
  27. 29 0
      src/views/vent/monitorManager/fanLocalMonitor1/fmfanLocal.three.ts
  28. 1553 0
      src/views/vent/monitorManager/fanLocalMonitor1/index.vue
  29. 5 23
      src/views/vent/monitorManager/workFaceMonitor/wokeFace.threejs.ts
  30. 5 2
      src/views/vent/monitorManager/workFaceMonitor/workFace.threejs.base.ts

+ 2 - 2
public/js/config.js

@@ -10,8 +10,8 @@ const History_Type = {
 }
 
 const VENT_PARAM = {
-  simulatedPassword: '123456', //(simulatedPassword 为空时有密码输入框弹出,不为空时不弹出密码输入框,无需输入密码)
-  // simulatedPassword: '',
+  // simulatedPassword: '123456', //(simulatedPassword 为空时有密码输入框弹出,不为空时不弹出密码输入框,无需输入密码)
+  simulatedPassword: '',
   showReport: true,
   isoOpenSso: 'false'
 }

+ 11 - 1
src/qiankun/index.ts

@@ -48,12 +48,22 @@ const mountMicroApp = (path, toPath?) => {
               ...args,
               headers: {
                 'Access-Control-Allow-Origin': '*',
+                'Content-Type': 'text/plain',
               },
               mode: 'cors',
               credentials: 'include',
             });
           }
-          return window.fetch(url, ...args);
+          return window.fetch(url, {
+            ...args,
+            headers: {
+              // 'Access-Control-Allow-Origin': '*',
+              'Content-Type': 'text/plain',
+            },
+            mode: 'cors',
+            credentials: 'include',
+          });
+          // return window.fetch(url, ...args);
         },
       }); // 手动加载子应用
     }

+ 1 - 0
src/utils/threejs/main.worker.ts

@@ -75,6 +75,7 @@ export function initModalWorker() {
     // 'workFace/workFace-hui_2024-03-04.glb',
     'workFace/workFace1-1_2024-04-09.glb',
     'workFace/workFace2-1_2024-04-09.glb',
+    'workFace/workFace_2024-09-19.glb',
   ];
 
   const db: any = new Dexie('DB');

+ 2 - 1
src/views/vent/deviceManager/configurationTable/adapters.ts

@@ -38,7 +38,8 @@ export function getFormattedText(data: any, formatter: string, defaultValue?: an
 
   const [__, prop] = res;
   const val = defaultValue === undefined ? '-' : defaultValue;
-  return formatter.replace(exp, _.get(data, prop, val));
+  const txt = _.get(data, prop);
+  return formatter.replace(exp, _.isNil(txt) ? val : txt);
 }
 
 /** 获取 formatter 需要取的源 prop,用于在一些不支持 formatter 的组件中使用 */

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

@@ -1,5 +1,3 @@
-import { ModulePositionMap, ModuleSizeMap } from './options';
-
 export interface Config {
   /** 模块的名称 */
   moduleName: string;
@@ -99,7 +97,7 @@ export interface ModuleDataBoard {
 
 export interface ModuleDataList {
   /** 列表预设的背景类型 */
-  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F';
+  type: 'timeline' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G';
   /** 读取数据时的基础路径,如果配置了 header,应接着 Config.deviceType 配取值路径,反之应配置详尽路径 */
   readFrom: string;
   /** 核心配置,每个列表项对应一项 */

+ 3 - 3
src/views/vent/home/configurable/components/detail/ComplexList.vue

@@ -146,8 +146,8 @@
     justify-content: space-between;
     text-align: center;
     padding: 0 10%;
-    margin-top: 15px;
-    height: 40px;
+    margin-top: 5px;
+    height: 33px;
 
     .list-item__label {
       font-size: 11px;
@@ -160,7 +160,7 @@
       height: 100%;
       display: flex;
       align-items: center;
-      flex-basis: 140px;
+      flex-basis: 100px;
       flex-grow: 1;
     }
     .list-item__title_B {

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

@@ -29,7 +29,7 @@
         prop: string;
         info: string;
       }[];
-      /** A B C D E */
+      /** A B C D E F G */
       type: string;
     }>(),
     {
@@ -180,6 +180,67 @@
   .list-item__content_F > div {
     flex-basis: 33.3%;
   }
+
+  .list_G {
+    background: none;
+  }
+  .list__wrapper_G {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+  }
+  .list-item_G {
+    width: 170px;
+    height: 85px;
+    align-items: center;
+    text-align: center;
+    border: 1px solid rgba(25, 237, 255, 0.4);
+    box-shadow: inset 0 0 10px rgba(0, 197, 255, 0.6);
+    background: rgba(0, 0, 0, 0.1);
+    margin: 5px 15px;
+  }
+  .list-item__content_G {
+    position: relative;
+    width: 100%;
+    height: 100%;
+  }
+  .list-item__content_G > .list-item__label {
+    width: 70px;
+    height: 100%;
+    left: 0;
+    position: absolute;
+    font-size: 20px;
+    line-height: 85px;
+  }
+  .list-item__content_G > .list-item__info {
+    width: 100px;
+    height: 40px;
+    line-height: 40px;
+    right: 0;
+    position: absolute;
+  }
+  .list-item__content_G > .list-item__value {
+    width: 100px;
+    height: 40px;
+    line-height: 40px;
+    top: 40px;
+    right: 0;
+    position: absolute;
+    text-shadow: 0 0 25px #00fbfe;
+    background: linear-gradient(0deg, #45d3fd, #45d3fd, #61ddb1, #61ddb1);
+    font-style: normal;
+    background-size: cover;
+    font-family: electronicFont;
+    font-size: 30px;
+    -webkit-background-clip: text;
+    background-clip: text;
+    -webkit-text-fill-color: transparent;
+    // position: relative;
+    // top: -8px;
+    font-family: Arial, Helvetica, sans-serif;
+    font-size: 18px;
+    color: aliceblue;
+  }
   // .list-item__icon_red {
   //   background-image: url('@/assets/images/home-container/configurable/warn_icon_5.png');
   // }

+ 241 - 108
src/views/vent/home/configurable/configurable.data.ts

@@ -1518,6 +1518,23 @@ export const testConfigBDDust: Config[] = [
                 },
               ],
             },
+            {
+              title: '${[2].sysNamme}',
+              contents: [
+                {
+                  label: '风险监测',
+                  value: '${[2].warnLevel}',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '最高粉尘浓度',
+                  value: '${[2].maxVal}',
+                  color: 'blue',
+                  info: '',
+                },
+              ],
+            },
           ],
         },
       ],
@@ -1559,12 +1576,12 @@ export const testConfigBDDust: Config[] = [
           readFrom: 'historyList',
           xAxis: [
             {
-              label: 'null',
+              label: '${time}',
             },
           ],
           yAxis: [
             {
-              label: 'A',
+              label: '浓度',
               align: 'left',
             },
           ],
@@ -1776,106 +1793,130 @@ export const testConfigBDDust: Config[] = [
   },
 ];
 
-// const BDfireMock = {
-//   allMineWarn: '低风险', //全矿井风险级别
-//   fireManageInfo: {
-//     //工作面风险监测
-//     totalNum: '5', //工作面总数
-//     dfxNum: '5', //工作面低风险数
-//     ybNum: '5', //工作面一般风险数
-//     jdNum: '5', //工作面较大风险数
-//     zdNum: '5', //工作面重大风险
-//     sysList: [
-//       {
-//         sysNamme: '工作面名称1', //工作面名称
-//         warnLevel: '低风险', //预警级别
-//         maxVal: '1.88', //最高温度
-//       },
-//       {
-//         sysNamme: '工作面名称2', //工作面名称
-//         warnLevel: '低风险', //预警级别
-//         maxVal: '1.88', //最高温度
-//       },
-//     ],
-//   },
-//   obfObj: {
-//     //密闭采空区监测系统
-//     maxC2H4: '', //乙烯最高值
-//     maxDp: '', //压差最大值
-//     maxTemperature: '', //温度最大值
-//     maxCo: '', //一氧化碳最大值
-//     maxCo2: '', //二氧化碳最大值
-//     maxCh4: '', //甲烷最大值
-//     maxC2h2: '', //乙炔最大值
-//     maxO2: '', //氧气最大值
-//   },
-//   btArray: [
-//     //工作面束管监测
-//     {
-//       name: 'CO', //数据名称(前端自己处理化学方程式的标识符)
-//       val: '0.2', //最大值
-//       strinstallpos: '位置1', //安装位置
-//       time: '2024-09-12 15:33:50',
-//     },
-//     {
-//       name: 'CO2', //数据名称(前端自己处理化学方程式的标识符)
-//       val: '0.3', //最大值
-//       strinstallpos: '位置1', //安装位置
-//       time: '2024-09-12 15:33:50',
-//     },
-//   ],
-//   pdArray: [
-//     //带式输送机防灭火监控系统
-//     {
-//       name: '光纤预警', //设备名称
-//       type: '最高温度', //参数类型
-//       val: '35.2', //参数值
-//     },
-//     {
-//       name: '一氧化碳预警',
-//       type: '最高浓度',
-//       val: '2.3',
-//     },
-//     {
-//       name: '烟雾预警',
-//       type: '最高浓度',
-//       val: '2.4',
-//     },
-//   ],
-//   dsArray: [
-//     //变电硐室防灭火监控系统
-//     {
-//       name: '光纤预警', //设备名称
-//       type: '最高温度', //参数类型
-//       val: '35.2', //参数值
-//     },
-//     {
-//       name: '一氧化碳预警',
-//       type: '最高浓度',
-//       val: '2.3',
-//     },
-//     {
-//       name: '烟雾预警',
-//       type: '最高浓度',
-//       val: '2.4',
-//     },
-//   ],
-//   aqjkArray: [
-//     //安全监控系统
-//     {
-//       strinstallpos: '位置1', //安装位置
-//       nowVal: '25.0', //温度
-//       warnLevel: '低风险', //预警级别
-//       time: '2024-09-12 15:33:50', //时间
-//     },
-//     {
-//       strinstallpos: '位置2', //安装位置
-//       nowVal: '25.0', //温度
-//       warnLevel: '低风险', //预警级别
-//       time: '2024-09-12 15:33:50', //时间
-//     },
-//   ],
-// };
+const BDfireMock = {
+  allMineWarn: '低风险', //全矿井风险级别
+  fireManageInfo: {
+    sysList: [
+      {
+        maxVal: 20.2,
+        sysId: 1746452629872402400,
+        warnLevel: '低风险',
+        sysNamme: '81203综放工作面',
+      },
+      {
+        maxVal: 29.6,
+        sysId: 1834591184917872600,
+        warnLevel: '低风险',
+        sysNamme: '上仓皮带',
+      },
+    ],
+    totalNum: 2,
+    jdNum: 0,
+    dfxNum: 2,
+    zdNum: 0,
+    ybNum: 0,
+  },
+  obfObj: {
+    //密闭采空区监测系统
+    maxC2H4: '', //乙烯最高值
+    maxDp: '', //压差最大值
+    maxTemperature: '', //温度最大值
+    maxCo: '', //一氧化碳最大值
+    maxCo2: '', //二氧化碳最大值
+    maxCh4: '', //甲烷最大值
+    maxC2h2: '', //乙炔最大值
+    maxO2: '', //氧气最大值
+  },
+  btArray: [
+    {
+      val: '0.0',
+      strinstallpos: '81202辅运1联巷',
+      name: 'CO',
+      time: '2024-09-18 16:15:40',
+    },
+    {
+      val: '0.84',
+      strinstallpos: '81202辅运1联巷',
+      name: 'CO2',
+      time: '2024-09-18 16:15:40',
+    },
+    {
+      val: '17.45',
+      strinstallpos: '81202辅运1联巷',
+      name: 'CH4',
+      time: '2024-09-18 16:15:40',
+    },
+    {
+      val: '0.0',
+      strinstallpos: '81202辅运1联巷',
+      name: 'C2H2',
+      time: '2024-09-18 16:15:40',
+    },
+    {
+      val: '0.0',
+      strinstallpos: '81202辅运1联巷',
+      name: 'C2H4',
+      time: '2024-09-18 16:15:40',
+    },
+    {
+      val: '20.35',
+      strinstallpos: '81203工作面上隅角',
+      name: 'O2',
+      time: '2024-09-18 16:15:40',
+    },
+  ],
+  pdArray: [
+    //带式输送机防灭火监控系统
+    {
+      name: '光纤预警', //设备名称
+      type: '最高温度', //参数类型
+      val: '35.2', //参数值
+    },
+    {
+      name: '一氧化碳预警',
+      type: '最高浓度',
+      val: '2.3',
+    },
+    {
+      name: '烟雾预警',
+      type: '最高浓度',
+      val: null,
+    },
+  ],
+  dsArray: [
+    //变电硐室防灭火监控系统
+    {
+      name: '光纤预警', //设备名称
+      type: '最高温度', //参数类型
+      val: '35.2', //参数值
+    },
+    {
+      name: '一氧化碳预警',
+      type: '最高浓度',
+      val: '2.3',
+    },
+    {
+      name: '烟雾预警',
+      type: '最高浓度',
+      val: '2.4',
+    },
+  ],
+  aqjkArray: [
+    //安全监控系统
+    {
+      strinstallpos: '位置1', //安装位置
+      nowVal: '25.0', //温度
+      warnLevel: '低风险', //预警级别
+      time: '2024-09-12 15:33:50', //时间
+    },
+    {
+      strinstallpos: '位置2', //安装位置
+      nowVal: '25.0', //温度
+      warnLevel: '低风险', //预警级别
+      time: '2024-09-12 15:33:50', //时间
+    },
+  ],
+};
 export const testConfigBDFire: Config[] = [
   {
     deviceType: '',
@@ -1940,17 +1981,17 @@ export const testConfigBDFire: Config[] = [
               ],
             },
             {
-              title: '${[0].sysNamme}',
+              title: '${[1].sysNamme}',
               contents: [
                 {
                   label: '风险监测',
-                  value: '${[0].warnLevel}',
+                  value: '${[1].warnLevel}',
                   color: 'blue',
                   info: '',
                 },
                 {
                   label: '最高温度',
-                  value: '${[0].maxVal}',
+                  value: '${[1].maxVal}',
                   color: 'blue',
                   info: '',
                 },
@@ -1995,7 +2036,7 @@ export const testConfigBDFire: Config[] = [
       gallery: [
         {
           type: 'G',
-          readFrom: '',
+          readFrom: 'obfObj',
           items: [
             {
               label: '一氧化碳',
@@ -2082,7 +2123,7 @@ export const testConfigBDFire: Config[] = [
           readFrom: 'btArray',
           items: [
             {
-              title: 'O',
+              title: 'CO',
               contents: [
                 {
                   label: '最大浓度',
@@ -2127,6 +2168,98 @@ export const testConfigBDFire: Config[] = [
                 },
               ],
             },
+            {
+              title: 'CH₄',
+              contents: [
+                {
+                  label: '最大浓度',
+                  value: '${[2].val}ppm',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '位置',
+                  value: '${[2].strinstallpos}',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '时间',
+                  value: '${[2].time}',
+                  color: 'blue',
+                  info: '',
+                },
+              ],
+            },
+            {
+              title: 'C₂H₂',
+              contents: [
+                {
+                  label: '最大浓度',
+                  value: '${[3].val}ppm',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '位置',
+                  value: '${[3].strinstallpos}',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '时间',
+                  value: '${[3].time}',
+                  color: 'blue',
+                  info: '',
+                },
+              ],
+            },
+            {
+              title: 'C₂H₄',
+              contents: [
+                {
+                  label: '最大浓度',
+                  value: '${[4].val}ppm',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '位置',
+                  value: '${[4].strinstallpos}',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '时间',
+                  value: '${[4].time}',
+                  color: 'blue',
+                  info: '',
+                },
+              ],
+            },
+            {
+              title: 'O₂',
+              contents: [
+                {
+                  label: '最大浓度',
+                  value: '${[5].val}ppm',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '位置',
+                  value: '${[5].strinstallpos}',
+                  color: 'blue',
+                  info: '',
+                },
+                {
+                  label: '时间',
+                  value: '${[5].time}',
+                  color: 'blue',
+                  info: '',
+                },
+              ],
+            },
           ],
         },
       ],
@@ -2169,7 +2302,7 @@ export const testConfigBDFire: Config[] = [
       list: [
         {
           type: 'F',
-          readFrom: 'pdArray',
+          readFrom: 'dsArray',
           items: [
             {
               label: '光纤预警',

+ 10 - 4
src/views/vent/home/configurable/dustBD.vue

@@ -53,7 +53,9 @@
       :visible="true"
       :page-type="pageType"
     />
-    <VentModal style="width: 100%; height: 100%; position: absolute; z-index: -1" />
+    <div style="width: 1000px; height: 570px; position: absolute; left: calc(50% - 500px); top: 60px">
+      <VentModal />
+    </div>
   </div>
 </template>
 <script lang="ts" setup>
@@ -102,14 +104,14 @@
 
     .top-bg {
       width: 100%;
-      height: 56px;
+      height: 86px;
       background: url(/@/assets/images/home-container/configurable/firehome/fire-title.png) no-repeat center;
       position: absolute;
       z-index: 1;
       .main-title {
-        height: 56px;
+        height: 86px;
         font-family: 'douyuFont';
-        font-size: 20px;
+        font-size: 26px;
         letter-spacing: 2px;
         display: flex;
         justify-content: center;
@@ -274,4 +276,8 @@
       cursor: pointer;
     }
   }
+
+  :deep(.loading-box) {
+    position: unset;
+  }
 </style>

+ 10 - 4
src/views/vent/home/configurable/fireBD.vue

@@ -53,7 +53,9 @@
       :visible="true"
       :page-type="pageType"
     />
-    <VentModal style="width: 100%; height: 100%; position: absolute; z-index: -1" />
+    <div style="width: 1000px; height: 570px; position: absolute; left: calc(50% - 500px); top: 60px">
+      <VentModal />
+    </div>
   </div>
 </template>
 <script lang="ts" setup>
@@ -103,14 +105,14 @@
 
     .top-bg {
       width: 100%;
-      height: 56px;
+      height: 86px;
       background: url(/@/assets/images/home-container/configurable/firehome/fire-title.png) no-repeat center;
       position: absolute;
       z-index: 1;
       .main-title {
-        height: 56px;
+        height: 86px;
         font-family: 'douyuFont';
-        font-size: 20px;
+        font-size: 26px;
         letter-spacing: 2px;
         display: flex;
         justify-content: center;
@@ -274,4 +276,8 @@
       line-height: 50px;
     }
   }
+
+  :deep(.loading-box) {
+    position: unset;
+  }
 </style>

+ 10 - 4
src/views/vent/home/configurable/index.vue

@@ -53,7 +53,9 @@
       :visible="true"
       :page-type="pageType"
     />
-    <VentModal style="width: 100%; height: 100%; position: absolute; z-index: -1" />
+    <div style="width: 1000px; height: 570px; position: absolute; left: calc(50% - 500px); top: 60px">
+      <VentModal />
+    </div>
   </div>
 </template>
 <script lang="ts" setup>
@@ -102,14 +104,14 @@
 
     .top-bg {
       width: 100%;
-      height: 56px;
+      height: 86px;
       background: url(/@/assets/images/home-container/configurable/firehome/fire-title.png) no-repeat center;
       position: absolute;
       z-index: 1;
       .main-title {
-        height: 56px;
+        height: 86px;
         font-family: 'douyuFont';
-        font-size: 20px;
+        font-size: 26px;
         letter-spacing: 2px;
         display: flex;
         justify-content: center;
@@ -274,4 +276,8 @@
       cursor: pointer;
     }
   }
+
+  :deep(.loading-box) {
+    position: unset;
+  }
 </style>

+ 95 - 47
src/views/vent/monitorManager/alarmMonitor/common/closeWall.vue

@@ -3,20 +3,26 @@
     <div class="title">
       <div class="box-container">
         <div class="contents">
-          <img src="../../../../../assets/images/fire/pie.png" alt="" />
-          <span class="text">{{ topContent.temperature }}</span>
-          <span class="dw">°C</span>
-        </div>
-        <div class="contents">
           <div class="text">
-            <span class="text-label">位置 : </span>
-            <span class="text-value">{{ topContent.position }}</span>
+            <div class="text-label">位置: </div>
+            <!-- <div class="text-value">{{ topContent.position }}</div> -->
+            <div class="text-value">
+              <a-select v-model:value="selectData" style="width: 360px" @change="changeSelect">
+                <a-select-option v-for="file in selectList" :key="file.label" :value="file.value">{{ file.label
+                  }}</a-select-option>
+              </a-select>
+            </div>
           </div>
           <div class="text">
             <span class="text-label">时间 : </span>
             <span class="text-value">{{ topContent.time }}</span>
           </div>
         </div>
+        <div class="contents">
+          <img src="../../../../../assets/images/fire/pie.png" alt="" />
+          <span class="text">{{ topContent.temperature }}</span>
+          <span class="dw">°C</span>
+        </div>
       </div>
       <div class="box-container">
         <div class="text1">
@@ -86,6 +92,10 @@ import warnZb from './warnZb.vue'
 let props = defineProps({
   listData: Object,
 });
+
+let selectSj = ref<any[]>([])
+let selectData = ref('')
+let selectList = reactive<any[]>([])
 let widthV = ref('75%')
 let heightV = ref('80%')
 let coordDw = ref<any[]>([47, 95])
@@ -99,7 +109,7 @@ let topContent = reactive({
   position: '',
   time: '',
   warnLevel: '',
-  smokeJd:'',
+  smokeJd: '',
 });
 //密闭参数列表
 let mbList = reactive([
@@ -227,6 +237,26 @@ function btnClick(item, ind) {
   }
 }
 
+function changeSelect(val) {
+  selectData.value = val
+  let data = selectSj.value.filter(v => v.strinstallpos == selectData.value)[0]
+  topContent.time = data.readTime || '--';
+  topContent.warnLevel = data.syswarnLevel_str
+  topContent.smokeJd = data.syswarnLevel_des
+
+  mbList[0].nd = data.readData.o2val || '--';
+  mbList[1].nd = data.readData.coval || '--';
+  mbList[2].nd = data.readData.co2val || '--';
+  mbList[3].nd = data.readData.chval || '--';
+  mbList[4].nd = data.readData.ch2val || '--';
+  mbList[5].nd = data.readData.gasval || '--';
+  mbList.forEach((el) => {
+    el.time1 = data ? data.readTime.substring(0, data.readTime.lastIndexOf(':')) : '--';
+    el.address = data ? data.strinstallpos : '--';
+  });
+  netStatus.value = data['netStatus']
+}
+
 watch(
   () => props.listData,
   (val) => {
@@ -234,26 +264,33 @@ watch(
     echartDataSg1.xData.length = 0;
     echartDataSg1.yData.length = 0;
     echartDataSgList.length = 0;
+    selectList.length = 0
     if (JSON.stringify(val) != '{}') {
       if (val.bundletube.length != 0) {
+        selectSj.value = val.bundletube
+        selectSj.value.forEach(el => {
+          selectList.push({ label: el.strinstallpos, value: el.strinstallpos })
+        })
+        selectData.value = selectData.value ? selectData.value : selectList[0].value
+        let dataVal = selectData.value ? selectSj.value.filter(v => v.strinstallpos == selectData.value)[0] : selectSj.value[0];
         topContent.temperature = val.temperature[0] ? val.temperature[0].readData.temperature : '--';
-        topContent.position = val.bundletube[0].strinstallpos || '--';
-        topContent.time = val.bundletube[0].readTime || '--';
-        topContent.warnLevel = val.bundletube[0].syswarnLevel_str
-        topContent.smokeJd = val.bundletube[0].syswarnLevel_des
-
-        mbList[0].nd = val.bundletube[0].readData.o2val || '--';
-        mbList[1].nd = val.bundletube[0].readData.coval || '--';
-        mbList[2].nd = val.bundletube[0].readData.co2val || '--';
-        mbList[3].nd = val.bundletube[0].readData.chval || '--';
-        mbList[4].nd = val.bundletube[0].readData.ch2val || '--';
-        mbList[5].nd = val.bundletube[0].readData.gasval || '--';
+        // topContent.position = dataVal.strinstallpos || '--';
+        topContent.time = dataVal.readTime || '--';
+        topContent.warnLevel = dataVal.syswarnLevel_str
+        topContent.smokeJd = dataVal.syswarnLevel_des
+
+        mbList[0].nd = dataVal.readData.o2val || '--';
+        mbList[1].nd = dataVal.readData.coval || '--';
+        mbList[2].nd = dataVal.readData.co2val || '--';
+        mbList[3].nd = dataVal.readData.chval || '--';
+        mbList[4].nd = dataVal.readData.ch2val || '--';
+        mbList[5].nd = dataVal.readData.gasval || '--';
         mbList.forEach((el) => {
-          el.time1 = val.bundletube[0] ? val.bundletube[0].readTime.substring(0, val.bundletube[0].readTime.lastIndexOf(':')) : '--';
-          el.address = val.bundletube[0] ? val.bundletube[0].strinstallpos : '--';
+          el.time1 = dataVal ? dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':')) : '--';
+          el.address = dataVal ? dataVal.strinstallpos : '--';
         });
-        netStatus.value = val.bundletube[0]['netStatus']
-        val.bundletube[0].history.forEach((v) => {
+        netStatus.value = dataVal['netStatus']
+        dataVal.history.forEach((v) => {
           echartDataSg1.xData.push(v.time);
           if (echartDataSg1.lengedData == 'O₂') {
             echartDataSg1.yData.push(v.o2val);
@@ -272,10 +309,10 @@ watch(
         });
       } else {
         topContent.temperature = 0;
-        topContent.position = '--';
+        // topContent.position = '--';
         topContent.time = '--';
         topContent.warnLevel = '--';
-        topContent.smokeJd='--'
+        topContent.smokeJd = '--'
         mbList[0].nd = '--';
         mbList[1].nd = '--';
         mbList[2].nd = '--';
@@ -337,6 +374,30 @@ watch(
         &:nth-child(1) {
           width: 40%;
           display: flex;
+          flex-direction: column;
+          justify-content: space-around;
+
+          .text {
+            font-size: 14px;
+            display: flex;
+            align-items: center;
+
+            .text-label {
+              color: #b3b8cc;
+              font-weight: bold;
+            }
+
+            .text-value {
+              font-family: 'douyuFont';
+              color: #3df6ff;
+              margin-left: 10px;
+            }
+          }
+        }
+
+        &:nth-child(2) {
+          width: 40%;
+          display: flex;
           justify-content: center;
           align-items: center;
 
@@ -360,28 +421,6 @@ watch(
             color: #b3b8cc;
           }
         }
-
-        &:nth-child(2) {
-          width: 60%;
-          display: flex;
-          flex-direction: column;
-          justify-content: space-around;
-
-          .text {
-            font-size: 14px;
-
-            .text-label {
-              color: #b3b8cc;
-              font-weight: bold;
-            }
-
-            .text-value {
-              font-family: 'douyuFont';
-              color: #3df6ff;
-              margin-left: 10px;
-            }
-          }
-        }
       }
 
       .text1 {
@@ -620,4 +659,13 @@ watch(
     }
   }
 }
+
+:deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
+  border: 1px solid #3ad8ff77 !important;
+  background-color: #ffffff00 !important;
+}
+
+:deep(.zxm-select-selection-item) {
+  color: #fff !important;
+}
 </style>

+ 387 - 344
src/views/vent/monitorManager/alarmMonitor/common/fireWork.vue

@@ -35,6 +35,12 @@
     <div class="bot-content">
       <div class="title">
         <div class="text">束管系统监测</div>
+        <div class="select-box">
+          <a-select v-model:value="selectData" style="width: 250px" @change="changeSelect">
+            <a-select-option v-for="file in selectList" :key="file.label" :value="file.value">{{ file.label
+              }}</a-select-option>
+          </a-select>
+        </div>
       </div>
       <div class="content">
         <div class="content-box" v-for="(item, index) in contentList" :key="index">
@@ -62,419 +68,456 @@
 </template>
 
 <script lang="ts" setup>
-  import { onMounted, ref, reactive, watch, defineProps } from 'vue';
-  import imgUrl from '../../../../../assets/images/fire/pie.png';
-  import echartLine from './echartLine.vue';
-  import echartLine1 from './echartLine1.vue';
-  import { topList, contentList } from '../common.data';
-
-  let props = defineProps({
-    listData: Object,
+import { onMounted, ref, reactive, watch, defineProps } from 'vue';
+import imgUrl from '../../../../../assets/images/fire/pie.png';
+import echartLine from './echartLine.vue';
+import echartLine1 from './echartLine1.vue';
+import { topList, contentList } from '../common.data';
+
+let props = defineProps({
+  listData: Object,
+});
+
+let selectSj = ref<any[]>([])
+let selectData = ref('')
+let selectList = reactive<any[]>([])
+let maxY = ref(2000);
+let echartDw = ref('(­°C)');
+//光钎测温-图表数据
+let echartDataGq = reactive({
+  maxData: {
+    lengedData: '当前温度',
+    data: [],
+  },
+  xData: [],
+});
+//束管监测-图表数据
+let echartDataSg = reactive({
+  xData: [],
+  yData: [],
+  lengedData: 'O₂',
+  lengedDataName: '(%)',
+});
+let echartDataSgList = reactive<any[]>([]);
+//束管实时数据选项点击
+function getSgClick(items) {
+  echartDataSg.xData.length = 0;
+  echartDataSg.yData.length = 0;
+  echartDataSg.lengedData = items.title;
+  echartDataSg.lengedDataName = items.dw;
+
+  switch (items.title) {
+    case 'O₂':
+      echartDataSgList.forEach((el) => {
+        echartDataSg.xData.push(el.time);
+        echartDataSg.yData.push(el.o2val);
+      });
+      break;
+    case 'C₂H₄':
+      echartDataSgList.forEach((el) => {
+        echartDataSg.xData.push(el.time);
+        echartDataSg.yData.push(el.ch2val);
+      });
+      break;
+    case 'CO':
+      echartDataSgList.forEach((el) => {
+        echartDataSg.xData.push(el.time);
+        echartDataSg.yData.push(el.coval);
+      });
+      break;
+    case 'CH₄':
+      echartDataSgList.forEach((el) => {
+        echartDataSg.xData.push(el.time);
+        echartDataSg.yData.push(el.chval);
+      });
+      break;
+    case 'CO₂':
+      echartDataSgList.forEach((el) => {
+        echartDataSg.xData.push(el.time);
+        echartDataSg.yData.push(el.co2val);
+      });
+      break;
+    case 'C₂H₂':
+      echartDataSgList.forEach((el) => {
+        echartDataSg.xData.push(el.time);
+        echartDataSg.yData.push(el.gasval);
+      });
+      break;
+  }
+}
+function changeSelect(val) {
+  selectData.value = val
+  let data = selectSj.value.filter(v => v.strinstallpos == selectData.value)[0]
+  contentList[0].list[0].value = data.readData.o2val;
+  contentList[0].list[1].value = data.readData.ch2val;
+  contentList[1].list[0].value = data.readData.coval;
+  contentList[1].list[1].value = data.readData.chval;
+  contentList[2].list[0].value = data.readData.co2val;
+  contentList[2].list[1].value = data.readData.gasval;
+  contentList.forEach((el) => {
+    el.list.forEach((v) => {
+      v.time = data.readTime.substring(0, data.readTime.lastIndexOf(':'));
+    });
   });
+}
 
   let maxY = ref(100);
-  let echartDw = ref('(­°C)');
-  //光钎测温-图表数据
-  let echartDataGq = reactive({
-    maxData: {
-      lengedData: '当前温度',
-      data: [],
-    },
-    xData: [],
-  });
-  //束管监测-图表数据
-  let echartDataSg = reactive({
-    xData: [],
-    yData: [],
-    lengedData: 'O₂',
-    lengedDataName: '(%)',
-  });
-  let echartDataSgList = reactive<any[]>([]);
-  //束管实时数据选项点击
-  function getSgClick(items) {
+watch(
+  () => props.listData,
+  (val, val1) => {
+    echartDataGq.xData.length = 0;
+    echartDataGq.maxData.data.length = 0;
+    echartDataSgList.length = 0;
     echartDataSg.xData.length = 0;
     echartDataSg.yData.length = 0;
-    echartDataSg.lengedData = items.title;
-    echartDataSg.lengedDataName = items.dw;
-
-    switch (items.title) {
-      case 'O₂':
-        echartDataSgList.forEach((el) => {
-          echartDataSg.xData.push(el.time);
-          echartDataSg.yData.push(el.o2val);
-        });
-        break;
-      case 'C₂H₄':
-        echartDataSgList.forEach((el) => {
-          echartDataSg.xData.push(el.time);
-          echartDataSg.yData.push(el.ch2val);
-        });
-        break;
-      case 'CO':
-        echartDataSgList.forEach((el) => {
-          echartDataSg.xData.push(el.time);
-          echartDataSg.yData.push(el.coval);
+    selectList.length = 0
+    if (JSON.stringify(val) != '{}') {
+      if (val.fiber.length != 0) {
+        topList[0].value = val.fiber[0].readData.fmax;
+        topList[1].value = val.fiber[0].readData.fmin;
+        topList[2].value = val.fiber[0].readData.favg;
+        topList[3].text = val.fiber[0].warnFlag ? '报警' : '正常';
+        JSON.parse(val.fiber[0].readData.fibreTemperature).forEach((el) => {
+          echartDataGq.xData.push(el.pos);
+          echartDataGq.maxData.data.push(el.value);
         });
-        break;
-      case 'CH₄':
-        echartDataSgList.forEach((el) => {
-          echartDataSg.xData.push(el.time);
-          echartDataSg.yData.push(el.chval);
-        });
-        break;
-      case 'CO₂':
-        echartDataSgList.forEach((el) => {
-          echartDataSg.xData.push(el.time);
-          echartDataSg.yData.push(el.co2val);
-        });
-        break;
-      case 'C₂H₂':
-        echartDataSgList.forEach((el) => {
-          echartDataSg.xData.push(el.time);
-          echartDataSg.yData.push(el.gasval);
-        });
-        break;
-    }
-  }
-
-  watch(
-    () => props.listData,
-    (val, val1) => {
-      echartDataGq.xData.length = 0;
-      echartDataGq.maxData.data.length = 0;
-      echartDataSgList.length = 0;
-      echartDataSg.xData.length = 0;
-      echartDataSg.yData.length = 0;
-      if (JSON.stringify(val) != '{}') {
-        if (val.fiber.length != 0) {
-          topList[0].value = val.fiber[0].readData.fmax;
-          topList[1].value = val.fiber[0].readData.fmin;
-          topList[2].value = val.fiber[0].readData.favg;
-          topList[3].text = val.fiber[0].warnFlag ? '报警' : '正常';
-          JSON.parse(val.fiber[0].readData.fibreTemperature).forEach((el) => {
-            echartDataGq.xData.push(el.pos);
-            echartDataGq.maxData.data.push(el.value);
-          });
-        } else {
-          topList[0].value = '--';
-          topList[1].value = '--';
-          topList[2].value = '--';
-          topList[3].text = '正常';
-        }
+      } else {
+        topList[0].value = '--';
+        topList[1].value = '--';
+        topList[2].value = '--';
+        topList[3].text = '正常';
+      }
 
-        if (val.bundletube.length != 0) {
-          contentList[0].list[0].value = val.bundletube[0].readData.o2val;
-          contentList[0].list[1].value = val.bundletube[0].readData.ch2val;
-          contentList[1].list[0].value = val.bundletube[0].readData.coval;
-          contentList[1].list[1].value = val.bundletube[0].readData.chval;
-          contentList[2].list[0].value = val.bundletube[0].readData.co2val;
-          contentList[2].list[1].value = val.bundletube[0].readData.gasval;
-          contentList.forEach((el) => {
-            el.list.forEach((v) => {
-              v.time = val.bundletube[0].readTime.substring(0, val.bundletube[0].readTime.lastIndexOf(':'));
-            });
+      if (val.bundletube.length != 0) {
+        selectSj.value = val.bundletube
+        selectSj.value.forEach(el => {
+          selectList.push({ label: el.strinstallpos, value: el.strinstallpos })
+        })
+        selectData.value=  selectData.value ?  selectData.value : selectList[0].value
+        let dataVal = selectData.value ? selectSj.value.filter(v => v.strinstallpos == selectData.value)[0] : selectSj.value[0];
+        contentList[0].list[0].value = dataVal.readData.o2val;
+        contentList[0].list[1].value = dataVal.readData.ch2val;
+        contentList[1].list[0].value = dataVal.readData.coval;
+        contentList[1].list[1].value = dataVal.readData.chval;
+        contentList[2].list[0].value = dataVal.readData.co2val;
+        contentList[2].list[1].value = dataVal.readData.gasval;
+        contentList.forEach((el) => {
+          el.list.forEach((v) => {
+            v.time = dataVal.readTime.substring(0, dataVal.readTime.lastIndexOf(':'));
           });
+        });
 
-          val.bundletube[0].history.forEach((el) => {
-            echartDataSg.xData.push(el.time);
-            if (echartDataSg.lengedData == 'O₂') {
-              echartDataSg.yData.push(el.o2val);
-            } else if (echartDataSg.lengedData == 'C₂H₄') {
-              echartDataSg.yData.push(el.ch2val);
-            } else if (echartDataSg.lengedData == 'C₂H₂') {
-              echartDataSg.yData.push(el.gasval);
-            } else if (echartDataSg.lengedData == 'CH₄') {
-              echartDataSg.yData.push(el.chval);
-            } else if (echartDataSg.lengedData == 'CO') {
-              echartDataSg.yData.push(el.coval);
-            } else if (echartDataSg.lengedData == 'CO₂') {
-              echartDataSg.yData.push(el.co2val);
-            }
-            echartDataSgList.push(el);
-          });
-        } else {
-          contentList[0].list[0].value = '--';
-          contentList[0].list[1].value = '--';
-          contentList[1].list[0].value = '--';
-          contentList[1].list[1].value = '--';
-          contentList[2].list[0].value = '--';
-          contentList[2].list[1].value = '--';
-          contentList.forEach((el) => {
-            el.list.forEach((v) => {
-              v.time = '--';
-            });
+        dataVal.history.forEach((el) => {
+          echartDataSg.xData.push(el.time);
+          if (echartDataSg.lengedData == 'O₂') {
+            echartDataSg.yData.push(el.o2val);
+          } else if (echartDataSg.lengedData == 'C₂H₄') {
+            echartDataSg.yData.push(el.ch2val);
+          } else if (echartDataSg.lengedData == 'C₂H₂') {
+            echartDataSg.yData.push(el.gasval);
+          } else if (echartDataSg.lengedData == 'CH₄') {
+            echartDataSg.yData.push(el.chval);
+          } else if (echartDataSg.lengedData == 'CO') {
+            echartDataSg.yData.push(el.coval);
+          } else if (echartDataSg.lengedData == 'CO₂') {
+            echartDataSg.yData.push(el.co2val);
+          }
+          echartDataSgList.push(el);
+        });
+      } else {
+        contentList[0].list[0].value = '--';
+        contentList[0].list[1].value = '--';
+        contentList[1].list[0].value = '--';
+        contentList[1].list[1].value = '--';
+        contentList[2].list[0].value = '--';
+        contentList[2].list[1].value = '--';
+        contentList.forEach((el) => {
+          el.list.forEach((v) => {
+            v.time = '--';
           });
-        }
+        });
       }
-    },
-    { deep: true }
-  );
+    }
+  },
+  { deep: true }
+);
 </script>
 
 <style lang="less" scoped>
-  .fireWork {
+.fireWork {
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+  box-sizing: border-box;
+
+  .work-nav {
+    height: 15%;
     width: 100%;
-    height: 100%;
-    padding: 20px;
-    box-sizing: border-box;
-
-    .work-nav {
-      height: 15%;
-      width: 100%;
-      margin-bottom: 20px;
-      background: url('../../../../../assets/images/fire/bj1.png') no-repeat center;
-      background-size: 100% 100%;
+    margin-bottom: 20px;
+    background: url('../../../../../assets/images/fire/bj1.png') no-repeat center;
+    background-size: 100% 100%;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+
+    .nav {
       display: flex;
-      justify-content: space-between;
+      justify-content: center;
       align-items: center;
 
-      .nav {
-        display: flex;
-        justify-content: center;
-        align-items: center;
-
-        &:nth-child(1) {
-          flex: 1;
-          height: 100%;
-          border-right: 2px solid;
-          border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
-        }
-
-        &:nth-child(2) {
-          flex: 1;
-          height: 100%;
-          border-right: 2px solid;
-          border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
-        }
-
-        &:nth-child(3) {
-          flex: 1;
-          height: 100%;
-          border-right: 2px solid;
-          border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
-        }
-
-        &:nth-child(4) {
-          flex: 0.6;
-          color: #b3b8cc;
-          font-size: 16px;
-          height: 100%;
-          border-right: 2px solid;
-          border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
-        }
-
-        &:nth-child(5) {
-          flex: 1.4;
-          height: 100%;
-
-          .percent {
-            width: 100%;
-            height: 82%;
-            padding: 0px 20px;
-            box-sizing: border-box;
-            display: flex;
-            flex-direction: column;
-            justify-content: space-around;
-
-            .title {
-              font-size: 14px;
-              padding: 5px 0px;
-              color: #b3b8cc;
-              text-align: center;
-            }
+      &:nth-child(1) {
+        flex: 1;
+        height: 100%;
+        border-right: 2px solid;
+        border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
+      }
 
-            .value {
-              display: flex;
-              justify-content: space-between;
+      &:nth-child(2) {
+        flex: 1;
+        height: 100%;
+        border-right: 2px solid;
+        border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
+      }
 
-              span {
-                font-family: 'douyuFont';
-                font-size: 18px;
-              }
-            }
-          }
-        }
+      &:nth-child(3) {
+        flex: 1;
+        height: 100%;
+        border-right: 2px solid;
+        border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
+      }
 
-        .pic {
-          width: 30%;
-          height: 82%;
+      &:nth-child(4) {
+        flex: 0.6;
+        color: #b3b8cc;
+        font-size: 16px;
+        height: 100%;
+        border-right: 2px solid;
+        border-image: linear-gradient(to bottom, transparent, rgba(2, 70, 136, 1), transparent) 1 1 1;
+      }
 
-          img {
-            width: 100%;
-            height: 100%;
-          }
-        }
+      &:nth-child(5) {
+        flex: 1.4;
+        height: 100%;
 
-        .content {
+        .percent {
+          width: 100%;
           height: 82%;
-          margin-left: 15px;
-          color: #fff;
+          padding: 0px 20px;
+          box-sizing: border-box;
           display: flex;
           flex-direction: column;
           justify-content: space-around;
 
-          span {
+          .title {
             font-size: 14px;
+            padding: 5px 0px;
+            color: #b3b8cc;
+            text-align: center;
+          }
 
-            &:nth-child(1) {
-              padding: 5px 0px;
-              color: #b3b8cc;
-            }
+          .value {
+            display: flex;
+            justify-content: space-between;
 
-            &:nth-child(2) {
+            span {
               font-family: 'douyuFont';
-              font-size: 16px;
-              color: #3df6ff;
+              font-size: 18px;
             }
           }
         }
       }
 
-      .nav:nth-child(1) .pic {
-        background: url('../../../../../assets/images/fire/max.svg') no-repeat center;
-        background-size: 50% 50%;
-      }
-
-      .nav:nth-child(2) .pic {
-        background: url('../../../../../assets/images/fire/min.svg') no-repeat center;
-        background-size: 50% 50%;
-      }
+      .pic {
+        width: 30%;
+        height: 82%;
 
-      .nav:nth-child(3) .pic {
-        background: url('../../../../../assets/images/fire/pj.svg') no-repeat center;
-        background-size: 50% 50%;
+        img {
+          width: 100%;
+          height: 100%;
+        }
       }
-    }
 
-    .center-echart {
-      width: 100%;
-      height: 32%;
-      padding: 10px;
-      margin-bottom: 20px;
-      box-sizing: border-box;
-      background: url('../../../../../assets/images/fire/bj1.png') no-repeat center;
-      background-size: 100% 100%;
-
-      .nav-title {
-        height: 30px;
+      .content {
+        height: 82%;
+        margin-left: 15px;
+        color: #fff;
         display: flex;
-        justify-content: space-between;
-        align-items: center;
+        flex-direction: column;
+        justify-content: space-around;
 
-        .title {
-          font-family: 'douyuFont';
+        span {
           font-size: 14px;
-          color: #fff;
-          // color: #3df6ff;
+
+          &:nth-child(1) {
+            padding: 5px 0px;
+            color: #b3b8cc;
+          }
+
+          &:nth-child(2) {
+            font-family: 'douyuFont';
+            font-size: 16px;
+            color: #3df6ff;
+          }
         }
       }
+    }
 
-      .echart-box {
-        width: 100%;
-        height: calc(100% - 30px);
+    .nav:nth-child(1) .pic {
+      background: url('../../../../../assets/images/fire/max.svg') no-repeat center;
+      background-size: 50% 50%;
+    }
+
+    .nav:nth-child(2) .pic {
+      background: url('../../../../../assets/images/fire/min.svg') no-repeat center;
+      background-size: 50% 50%;
+    }
+
+    .nav:nth-child(3) .pic {
+      background: url('../../../../../assets/images/fire/pj.svg') no-repeat center;
+      background-size: 50% 50%;
+    }
+  }
+
+  .center-echart {
+    width: 100%;
+    height: 32%;
+    padding: 10px;
+    margin-bottom: 20px;
+    box-sizing: border-box;
+    background: url('../../../../../assets/images/fire/bj1.png') no-repeat center;
+    background-size: 100% 100%;
+
+    .nav-title {
+      height: 30px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+
+      .title {
+        font-family: 'douyuFont';
+        font-size: 14px;
+        color: #fff;
+        // color: #3df6ff;
       }
     }
 
-    .bot-content {
-      position: relative;
+    .echart-box {
       width: 100%;
-      height: calc(53% - 40px);
-      padding: 10px 10px 0px 10px;
-      box-sizing: border-box;
-      background: url('../../../../../assets/images/fire/bj1.png') no-repeat center;
-      background-size: 100% 100%;
+      height: calc(100% - 30px);
+    }
+  }
 
-      .title {
-        height: 30px;
-        display: flex;
-        justify-content: space-between;
+  .bot-content {
+    position: relative;
+    width: 100%;
+    height: calc(53% - 40px);
+    padding: 10px 10px 0px 10px;
+    box-sizing: border-box;
+    background: url('../../../../../assets/images/fire/bj1.png') no-repeat center;
+    background-size: 100% 100%;
 
-        .text {
-          height: 30px;
-          line-height: 30px;
-          font-family: 'douyuFont';
-          font-size: 14px;
-          color: #fff;
-        }
+    .title {
+      height: 35px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 10px;
+
+      .text {
+        // height: 30px;
+        // line-height: 30px;
+        font-family: 'douyuFont';
+        font-size: 14px;
+        color: #fff;
       }
+    }
 
-      .content {
-        height: calc(100% - 30px);
+    .content {
+      height: calc(100% - 45px);
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+
+      .content-box {
+        width: 100%;
+        height: 29%;
         display: flex;
-        flex-direction: column;
         justify-content: space-between;
+        margin-top: 0px !important;
 
-        .content-box {
-          width: 100%;
-          height: 29%;
-          display: flex;
-          justify-content: space-between;
-          margin-top: 0px !important;
-
-          .box-item {
-            position: relative;
-            width: 16%;
-            height: 100%;
-            background: url('../../../../../assets/images/fire/14174.png') no-repeat center;
+        .box-item {
+          position: relative;
+          width: 16%;
+          height: 100%;
+          background: url('../../../../../assets/images/fire/14174.png') no-repeat center;
+          background-size: 100% 100%;
+          cursor: pointer;
+
+          .content-title {
+            position: absolute;
+            left: 50%;
+            top: 0;
+            transform: translate(-50%);
+            color: #fff;
+            font-size: 14px;
+          }
+
+          .content-item {
+            position: absolute;
+            width: 93%;
+            height: 27%;
+            display: flex;
+            align-items: center;
+            padding: 0px 10px;
+            box-sizing: border-box;
+            background: url('../../../../../assets/images/fire/contetn.png') no-repeat center;
             background-size: 100% 100%;
-            cursor: pointer;
+            color: #fff;
+            font-size: 14px;
 
-            .content-title {
-              position: absolute;
+            &:nth-child(2) {
               left: 50%;
-              top: 0;
+              top: 28%;
               transform: translate(-50%);
-              color: #fff;
-              font-size: 14px;
+              display: flex;
+              justify-content: space-between;
             }
 
-            .content-item {
-              position: absolute;
-              width: 93%;
-              height: 27%;
+            &:nth-child(3) {
+              left: 50%;
+              top: 62%;
+              transform: translate(-50%);
               display: flex;
-              align-items: center;
-              padding: 0px 10px;
-              box-sizing: border-box;
-              background: url('../../../../../assets/images/fire/contetn.png') no-repeat center;
-              background-size: 100% 100%;
-              color: #fff;
-              font-size: 14px;
-
-              &:nth-child(2) {
-                left: 50%;
-                top: 28%;
-                transform: translate(-50%);
-                display: flex;
-                justify-content: space-between;
-              }
-
-              &:nth-child(3) {
-                left: 50%;
-                top: 62%;
-                transform: translate(-50%);
-                display: flex;
-                justify-content: space-between;
-              }
-
-              .bolds {
-                font-family: 'douyuFont';
-                color: #3df6ff;
-                font-size: 12px;
-              }
+              justify-content: space-between;
+            }
+
+            .bolds {
+              font-family: 'douyuFont';
+              color: #3df6ff;
+              font-size: 12px;
             }
           }
         }
       }
+    }
 
-      .echart-box {
-        position: absolute;
-        left: 50%;
-        top: 50px;
-        transform: translate(-50%, 0);
-        width: 66%;
-        height: calc(100% - 50px);
-      }
+    .echart-box {
+      position: absolute;
+      left: 50%;
+      top: 50px;
+      transform: translate(-50%, 0);
+      width: 66%;
+      height: calc(100% - 50px);
     }
   }
+}
+
+:deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
+  border: 1px solid #3ad8ff77 !important;
+  background-color: #ffffff00 !important;
+}
+
+:deep(.zxm-select-selection-item) {
+  color: #fff !important;
+}
 </style>

+ 12 - 13
src/views/vent/monitorManager/alarmMonitor/index.vue

@@ -449,26 +449,24 @@ async function getList() {
       iconsMonitor[el].closeCount = res.info.devicekindInfo[el].netstatus
     }
   });
-  fireMonitor[0].value =
-    res.info.sysInfo.fireS.summaryInfo.external.temperature && res.info.sysInfo.fireS.summaryInfo.external.temperature.maxlevel == '0'
-      ? '正常'
-      : '';
-  fireMonitor[1].value =
-    res.info.sysInfo.fireS.summaryInfo.external.smokeval &&
+  fireMonitor[0].value = res.info.sysInfo.fireS.summaryInfo ? res.info.sysInfo.fireS.summaryInfo.external.temperature && res.info.sysInfo.fireS.summaryInfo.external.temperature.maxlevel == '0'
+    ? '正常' : '' : '';
+  fireMonitor[1].value =res.info.sysInfo.fireS.summaryInfo ?  res.info.sysInfo.fireS.summaryInfo.external.smokeval &&
       res.info.sysInfo.fireS.summaryInfo.external.smokeval.maxlevel &&
       res.info.sysInfo.fireS.summaryInfo.external.smokeval.maxlevel == '0'
       ? '正常'
-      : '';
-  fireMonitor[2].value =
-    res.info.sysInfo.fireS.summaryInfo.external.fireval &&
+      : '' : '';
+   
+  fireMonitor[2].value =res.info.sysInfo.fireS.summaryInfo ?  res.info.sysInfo.fireS.summaryInfo.external.fireval &&
       res.info.sysInfo.fireS.summaryInfo.external.fireval.maxlevel &&
       res.info.sysInfo.fireS.summaryInfo.external.fireval.maxlevel == '0'
       ? '正常'
-      : '';
-  fireMonitor[3].value =
-    res.info.sysInfo.fireS.summaryInfo.external.coval && res.info.sysInfo.fireS.summaryInfo.external.coval.value
+      : '' : '';
+   
+  fireMonitor[3].value = res.info.sysInfo.fireS.summaryInfo ?  res.info.sysInfo.fireS.summaryInfo.external.coval && res.info.sysInfo.fireS.summaryInfo.external.coval.value
       ? res.info.sysInfo.fireS.summaryInfo.external.coval.value
-      : '';
+      : '' : '';
+   
 
   if (res.bundletubeInfo && res.bundletubeInfo.msgTxt.length != 0 && res.bundletubeInfo.msgTxt[0].datalist.length != 0) {
     res.bundletubeInfo.msgTxt[0].datalist.forEach((el, ind) => {
@@ -706,6 +704,7 @@ onUnmounted(() => {
           .all-count,
           .warn-count,
           .close-count {
+
             // margin: 0px 5px;
             .num-count {
               font-family: 'douyuFont';

+ 364 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/DetailModal.vue

@@ -0,0 +1,364 @@
+<template>
+  <BasicModal @register="register" title="风机详情" width="1600px" v-bind="$attrs" @ok="onSubmit" @cancel="onSubmit" :defaultFullscreen="true">
+    <div class="detail-box">
+      <div class="left-box">
+        <SvgPreview :data-model="data_model" :canvas-drag="false" />
+      </div>
+      <div class="right-box" v-if="activeBox == 1">
+        <div class="right-title">二部胶带机移变移动变电站控制详情</div>
+        <div class="detail-container">
+          <div class="detail-control">
+            <div class="control-item">高压分闸</div>
+            <div class="control-item">高压合闸</div>
+            <div class="control-item">高压复位</div>
+            <div class="control-item">低压复位</div>
+          </div>
+          <div class="right-detail-box">
+            <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
+              <a-tab-pane key="1" tab="运行状态">
+                <div class="detail-state">
+                  <div class="detail-item">
+                    <div class="item-title">高压侧</div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>运行状态</div>
+                      <div>正常</div>
+                    </div>
+                    <div v-for="(item, key) in transformMobileH" :key="key" class="vent-flex-row-between detail-item-row">
+                      <div>{{ item.title }}</div>
+                      <div>-</div>
+                    </div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>故障代码</div>
+                      <div>正常</div>
+                    </div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>分合闸状态</div>
+                      <div>正常</div>
+                    </div>
+                  </div>
+                  <div class="detail-item">
+                    <div class="item-title">低压侧</div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>运行状态</div>
+                      <div>正常</div>
+                    </div>
+                    <div v-for="(item, key) in transformMobileL" :key="key" class="vent-flex-row-between detail-item-row">
+                      <div>{{ item.title }}</div>
+                      <div>-</div>
+                    </div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>故障代码</div>
+                      <div>正常</div>
+                    </div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>分合闸状态</div>
+                      <div>正常</div>
+                    </div>
+                  </div>
+                </div>
+              </a-tab-pane>
+              <a-tab-pane key="2" tab="保护使能">
+                <div class="detail-state">
+                  <div class="detail-item">
+                    <div class="item-title">高压侧</div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>运行状态</div>
+                      <div>正常</div>
+                    </div>
+                    <div v-for="(item, key) in protectionEnableH" :key="key" class="vent-flex-row-between detail-item-row">
+                      <div>{{ item.title }}</div>
+                      <div>-</div>
+                    </div>
+                  </div>
+                  <div class="detail-item">
+                    <div class="item-title">低压侧</div>
+                    <div class="vent-flex-row-between detail-item-row">
+                      <div>运行状态</div>
+                      <div>正常</div>
+                    </div>
+                    <div v-for="(item, key) in protectionEnableL" :key="key" class="vent-flex-row-between detail-item-row">
+                      <div>{{ item.title }}</div>
+                      <div>-</div>
+                    </div>
+                  </div>
+                </div>
+              </a-tab-pane>
+            </a-tabs>
+          </div>
+        </div>
+      </div>
+      <div class="right-box" v-if="activeBox == 2">
+        <div class="right-title">电光馈电</div>
+        <div class="detail-container">
+          <div class="detail-control">
+            <div class="control-item">分闸</div>
+            <div class="control-item">合闸</div>
+            <div class="control-item">复位</div>
+          </div>
+          <div class="right-detail-box">
+            <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
+              <a-tab-pane key="1" tab="运行状态">
+                <template v-for="(electric, key) in electricMonitor" :key="index">
+                  <div class="padding-20">
+                    <a-divider style="border-color: #1580cc; color: #49b3ff; font-weight: 600; font-size: 14px" orientation="left">{{
+                      key
+                    }}</a-divider>
+                    <div class="data-group">
+                      <div class="data-item" v-for="(item, index) in electric" :key="index">
+                        <div class="title">{{ item.title }}</div>
+                        <div v-if="key !== '保护状态'" class="value">-</div>
+                        <div v-else class="state-box">
+                          <span class="signal-round signal-round-blue"></span><span class="state vent-margin-l-8"></span>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </template>
+              </a-tab-pane>
+              <a-tab-pane key="2" tab="定值设定">
+                <div class="padding-20">
+                  <a-divider style="border-color: #1580cc; color: #49b3ff; font-weight: 600; font-size: 14px" orientation="left">保护状态</a-divider>
+                  <div class="data-group">
+                    <div class="data-item" v-for="(item, index) in electricState" :key="index">
+                      <div class="title">{{ item.title }}</div>
+                      <div class="value">{{ item.value }}</div>
+                    </div>
+                  </div>
+                </div>
+              </a-tab-pane>
+            </a-tabs>
+          </div>
+        </div>
+      </div>
+      <div class="right-box" v-if="activeBox == 3">
+        <div class="right-title">电光风机开关详情</div>
+        <div class="detail-container">
+          <div class="detail-control">
+            <div class="control-item">分闸</div>
+            <div class="control-item">合闸</div>
+            <div class="control-item">复位</div>
+          </div>
+          <div class="right-detail-box">
+            <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
+              <a-tab-pane key="1" tab="运行状态">
+                <div class="detail-state">
+                  <div class="detail-item">
+                    <div class="item-title">备风机</div>
+                    <template v-for="(fanState, key) in fanControlState1" :key="index">
+                      <div class="padding-20">
+                        <a-divider style="border-color: #1580cc; color: #49b3ff; font-weight: 600; font-size: 14px" orientation="left">{{
+                          key
+                        }}</a-divider>
+                        <div class="data-group data-group1">
+                          <div class="data-item" v-for="(item, key1) in fanState" :key="key1">
+                            <div class="title">{{ key1 }}</div>
+                            <div class="value" v-for="(obj, key2) in item" :key="key2">{{ obj.value }}</div>
+                          </div>
+                        </div>
+                      </div>
+                    </template>
+                  </div>
+                  <div class="detail-item">
+                    <div class="item-title">主风机</div>
+                    <template v-for="(fanState, key) in fanControlState2" :key="index">
+                      <div class="padding-20">
+                        <a-divider style="border-color: #1580cc; color: #49b3ff; font-weight: 600; font-size: 14px" orientation="left">{{
+                          key
+                        }}</a-divider>
+                        <div class="data-group data-group1">
+                          <div class="data-item" v-for="(item, key1) in fanState" :key="key1">
+                            <div class="title">{{ key1 }}</div>
+                            <div class="value" v-for="(obj, key2) in item" :key="key2">{{ obj.value }}</div>
+                          </div>
+                        </div>
+                      </div>
+                    </template>
+                  </div>
+                </div>
+              </a-tab-pane>
+              <a-tab-pane key="2" tab="保护使能">
+                <div class="detail-state">
+                  <div class="detail-item">
+                    <div class="item-title">主风机</div>
+                    <div v-for="(item, key) in fanSetting1" :key="key" class="vent-flex-row-between detail-item-row">
+                      <div>{{ item.title }}</div>
+                      <div class="value">{{ item.value }}</div>
+                    </div>
+                  </div>
+                  <div class="detail-item">
+                    <div class="item-title">备风机</div>
+                    <div v-for="(item, key) in fanSetting2" :key="key" class="vent-flex-row-between detail-item-row">
+                      <div>{{ item.title }}</div>
+                      <div class="value">{{ item.value }}</div>
+                    </div>
+                  </div>
+                </div>
+              </a-tab-pane>
+            </a-tabs>
+          </div>
+        </div>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+  import { onMounted, ref, defineEmits, onUnmounted, watch } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import {
+    transformMobileH,
+    transformMobileL,
+    protectionEnableH,
+    protectionEnableL,
+    electricMonitor,
+    electricState,
+    fanControlState1,
+    fanControlState2,
+    fanSetting1,
+    fanSetting2,
+    data_model,
+  } from '../fanLocal.data.ts';
+  import { SvgPreview } from 'mky-svg';
+
+  const emit = defineEmits(['close', 'register']);
+  const props = defineProps({});
+  const activeKey = ref('1');
+  const activeBox = ref(3);
+  // 注册 modal
+  const [register, { closeModal }] = useModalInner();
+
+  const tabChange = (key) => {
+    activeKey.value = key;
+  };
+
+  async function onSubmit() {
+    emit('close');
+    closeModal();
+  }
+
+  onMounted(async () => {});
+  onUnmounted(() => {});
+</script>
+<style scoped lang="less">
+  @import '/@/design/vent/color.less';
+  @import '/@/design/vent/modal.less';
+  @import 'mky-svg/style.css';
+
+  @ventSpace: zxm;
+  .detail-box {
+    width: 100%;
+    height: 100%;
+    padding: 10px;
+    display: flex;
+    justify-content: space-between;
+
+    .left-box {
+      width: 800px;
+      height: 100%;
+      // height: initial;
+      border-right: 1px solid #ffffff22;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      font-size: 30px;
+      margin-right: 10px;
+    }
+    .right-box {
+      flex: 1;
+      height: 100%;
+      .right-title {
+        line-height: 60px;
+        background: #ffffff11;
+        margin-bottom: 2px;
+        text-align: center;
+        font-size: 20px;
+        letter-spacing: 2px;
+        color: #f0f0f0;
+      }
+      .detail-container {
+        height: calc(100% - 60px);
+        display: flex;
+        justify-content: space-between;
+
+        .detail-control {
+          width: 300px;
+          height: initial;
+          display: flex;
+          flex-direction: column;
+          background: #ffffff11;
+          margin-right: 10px;
+          padding: 10px;
+          .control-item {
+          }
+        }
+        .right-detail-box {
+          flex: 1;
+          background: #ffffff11;
+          padding-bottom: 40px;
+          .detail-state {
+            width: 100%;
+            display: flex;
+            justify-content: space-between;
+          }
+          .detail-item {
+            flex: 1;
+            padding: 0 40px;
+            color: #fff;
+            .item-title {
+              line-height: 60px;
+              font-size: 24px;
+              text-align: center;
+            }
+            .detail-item-row {
+              padding: 10px 0;
+            }
+          }
+        }
+      }
+      .value {
+        color: #00eefffe;
+      }
+    }
+  }
+
+  .data-group {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    padding: 0 20px 8px 20px;
+    color: #fff;
+    .data-item {
+      width: calc(50% - 20px);
+      display: flex;
+      justify-content: space-between;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
+      margin: 4px 0;
+    }
+    .value {
+      color: #00eefffe;
+    }
+    .data-item1 {
+      width: 100%;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39a3ff00, #39a3ff10, #39a3ff02);
+      margin: 4px 0;
+    }
+  }
+  .data-group1 {
+    .data-item {
+      width: calc(100% - 20px);
+      .title {
+        width: 80px;
+      }
+    }
+  }
+  .padding-20 {
+    padding: 20px;
+  }
+  .tabs-box {
+    width: 100%;
+  }
+  :deep(.@{ventSpace}-tabs-nav) {
+    padding: 0 20px;
+  }
+</style>

+ 943 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/conditionAssistance.vue

@@ -0,0 +1,943 @@
+<template>
+  <BasicModal
+    @register="register"
+    title="局部通风机运行工况智能决策"
+    :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }"
+    :width="isComputeGas ? '1400px' : '950px'"
+    v-bind="$attrs"
+    @ok="onSubmit"
+    :closeFunc="onCancel"
+    :canFullscreen="false"
+    :destroyOnClose="true"
+    :footer="null"
+    :maskClosable="false"
+  >
+    <div class="modal-box">
+      <div v-if="isComputeGas" class="left-box" style="width: 550px; height: 400px">
+        <BarAndLine
+          class="echarts-line"
+          xAxisPropType="time"
+          :dataSource="monitorData"
+          height="400px"
+          :chartsColumns="chartsColumnList"
+          :option="echatsOption"
+          chartsType="listMonitor"
+        />
+      </div>
+      <div class="center-box">
+        <a-spin :spinning="loadding" tip="正在计算,请稍等。。。">
+          <div ref="ChartRef" class="info-echarts" :style="{ width: isComputeGas ? '450px' : '520px', height: '400px' }"></div>
+        </a-spin>
+      </div>
+      <div class="right-box">
+        <!-- <div class="box-title">曲线方程</div> -->
+        <dv-decoration7 style="height: 20px">
+          <div class="box-title">曲线方程</div>
+        </dv-decoration7>
+        <div class="info-lines">
+          <div v-for="(item, index) in lineEquation" class="info-item" :key="index">
+            <div class="title">{{ item }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="tip-box">
+        <div class="title">最佳工况点 <SendOutlined class="ml-5px" /></div>
+        <div class="tip-container" :style="{ width: isComputeGas ? '898px' : '400px' }">
+          <template v-if="resultObj && isHaCross">
+            <div class="ml-10px">
+              <span>频率:</span>
+              <span style="color: #d066ff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.Hz) }}Hz</span>
+            </div>
+            <div class="ml-10px">
+              <span>风量:</span>
+              <span style="color: #3adeff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.x) }} m³/min</span>
+            </div>
+            <div class="ml-10px">
+              <span>负压</span>
+              <span style="color: #ffbe34; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.y) }} Pa</span>
+            </div>
+          </template>
+          <div v-else-if="isHaCross" class="ml-10px">暂无</div>
+          <div v-else style="color: #ffbe34; padding: 0 10px; font-weight: 600" class="ml-10px">无有效工况点</div>
+        </div>
+      </div>
+    </div>
+    <div class="setting-box">
+      <div class="right-inputs">
+        <div class="vent-flex-row">
+          <div class="input-title">风量(m³/min):</div>
+          <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uQ1" />
+          <div class="input-title">风压(Pa):</div>
+          <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uH" />
+          <div v-if="!isComputeGas" class="btn btn1" @click="makeLine">决策工况</div>
+          <template v-else>
+            <div class="btn btn1" @click="startCompute">一键调控</div>
+            <div class="btn btn1" @click="resetCompute">一键复位</div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+  //ts语法
+  import { ref, onMounted, reactive, nextTick, computed } from 'vue';
+  import echarts from '/@/utils/lib/echarts';
+  import { option, initData, fanInfoData, chartsColumnList, echatsOption } from '../fanLocal.data';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useForm } from '/@/components/Form/index';
+  import { Input, InputNumber } from 'ant-design-vue';
+  import { Decoration7 as DvDecoration7 } from '@kjgl77/datav-vue3';
+  import { message } from 'ant-design-vue';
+  import { formatNum } from '/@/utils/ventutil';
+  import BarAndLine from '/@/components/chart/BarAndLine.vue';
+  import { cloneDeep } from 'lodash-es';
+  import dayjs from 'dayjs';
+  import { SendOutlined } from '@ant-design/icons-vue';
+
+  const emit = defineEmits(['close', 'register', 'openModal']);
+  const props = defineProps({
+    dataSource: {
+      type: Array,
+      default: () => [],
+    },
+    frequency: {
+      type: Number,
+      default: 30,
+    },
+    m3: {
+      type: Number,
+      default: 670.8,
+    },
+    // gasWarningMax: { type: Number, default: 0.5 },
+    // gasWarningVal: { type: Number, default: 0.6 },
+    // windQuantity: { type: Number, default: 635.84 },
+  });
+  type AssistanceItemType = {
+    angle: number;
+    Hz: number;
+    a: number;
+    b: number;
+    c: number;
+    min: number;
+    max: number;
+  };
+
+  // 注册 modal
+  const [register, { closeModal }] = useModalInner((data) => {
+    nextTick(() => {
+      computeAssistance();
+      if (option['xAxis']) option['xAxis']['data'] = xData;
+      option['series'] = yDataList;
+      if (JSON.stringify(data) !== '{}') {
+        uQ1.value = Number(data['m3']);
+        uHz.value = Math.ceil(data['frequency']);
+        gasWarningVal.value = data['gasWarningVal'];
+        isComputeGas.value = true;
+        nextTick(() => {
+          computeUH(data['frequency'], data['m3']);
+          initEcharts();
+          setTimeout(() => {
+            // 根据频率计算uH
+            makeLine();
+          }, 2000);
+        });
+      } else {
+        initEcharts();
+        isComputeGas.value = false;
+      }
+    });
+  });
+  const loadding = ref<boolean>(false);
+  const formShow = ref(false);
+  const formType = ref('');
+  const ChartRef = ref();
+  const myChart = ref();
+  const refresh = ref(true);
+  const xDataMax = 1200;
+  let xDataMin = 0;
+  const xData: any[] = [];
+  const yDataList: [] = [];
+  let lineNum = 0;
+  const lineEquation = ref<string[]>([]);
+  const assistanceData = ref([]);
+  const monitorData = ref([]);
+  const gasWarningVal = ref(0);
+  const gasWarningMax = ref(0.5);
+  const isComputeGas = ref(false);
+  const isStartCompute = ref(0);
+  const uHz = ref(0);
+  const uQ1 = ref(0);
+  const uQ = computed(() => {
+    if (uQ1.value) {
+      if (gasWarningVal.value) {
+        return ((uQ1.value * gasWarningVal.value) / gasWarningMax.value) * 1.08;
+      }
+      return uQ1.value;
+    } else {
+      return 0;
+    }
+  });
+  const uH = ref<number | undefined>(undefined); //  - 1000
+  const isHaCross = ref(true);
+  const resultObj = ref<{ x: number; y: number; Hz: number } | null>(null);
+
+  const [registerForm, {}] = useForm({
+    labelWidth: 120,
+    actionColOptions: {
+      span: 24,
+    },
+    compact: true,
+    showSubmitButton: true,
+    submitButtonOptions: {
+      text: '提交',
+      preIcon: '',
+    },
+    showResetButton: true,
+    resetButtonOptions: {
+      text: '关闭',
+      preIcon: '',
+    },
+    resetFunc: async () => {
+      formShow.value = false;
+    },
+  });
+
+  function computeAssistance() {
+    assistanceData.value = initData();
+    lineNum = 0;
+    const assistanceDataList = [];
+    const lineEquationList: string[] = [];
+    for (const key in assistanceData.value) {
+      const item = assistanceData.value[key];
+      assistanceDataList.push(item);
+      lineEquationList.push(
+        `H${parseInt(item['Hz'])} = ${item['a']}Q² ${Number(item['b']) > 0 ? '+' : '-'} ${Math.abs(Number(item['b'])).toFixed(4)}Q ${
+          Number(item['c']) > 0 ? '+' : '-'
+        } ${Math.abs(Number(item['c'])).toFixed(4)}`
+      );
+    }
+    lineEquation.value = lineEquationList;
+    lineNum = assistanceDataList.length;
+    xDataMin =
+      Math.min.apply(
+        Math,
+        assistanceDataList.map((item) => {
+          return item.min;
+        })
+      ) - 100;
+    // const xDataMax = Math.max.apply(Math, assistanceDataList.map(item => { return item.max }))
+    fanInfoData.flfw = `${xDataMin}~${xDataMax}`;
+    const computeItem = (item: AssistanceItemType) => {
+      const min = item.min;
+      const max = item.max;
+      const HList: number[] = [];
+      for (let i = xDataMin; i <= xDataMax; i++) {
+        if (i < min) {
+          HList.push(null);
+        } else if (i > max) {
+          HList.push(null);
+        } else {
+          HList.push(item.a * i * i + item.b * i + item.c);
+        }
+      }
+      return HList;
+    };
+
+    for (const key in assistanceData.value) {
+      const element: AssistanceItemType = assistanceData.value[key];
+      const yData: number[] = computeItem(element);
+      const series = {
+        type: 'line',
+        name: `${element['Hz']}Hz`,
+        smooth: true,
+        showSymbol: false,
+        symbol: 'none',
+        emphasis: {
+          focus: 'series',
+        },
+        itemStyle: { normal: { label: { show: true } } },
+        lineStyle: {
+          width: 1,
+          color: '#ffffff88',
+        },
+        zlevel: 0,
+        z: 1,
+        endLabel: {
+          show: true,
+          formatter: '{a}',
+          distance: 0,
+          color: '#39E9FE99',
+          backgroundColor: 'transparent',
+          padding: [3, 3, 2, 3],
+        },
+        data: yData,
+      };
+
+      yDataList.push(series);
+    }
+
+    for (let i = xDataMin; i <= xDataMax; i++) {
+      xData.push(i);
+    }
+  }
+
+  function computeUH(Hz: number, uQ: number) {
+    const equation = assistanceData.value.find((item) => {
+      return Math.ceil(Hz) == item['Hz'];
+    });
+    if (equation) {
+      const uHMax = Math.round((equation['a'] * equation['min'] * equation['min'] + equation['b'] * equation['min'] + equation['c']) * 100) / 100;
+      const uHMin = Math.round((equation['a'] * equation['max'] * equation['max'] + equation['b'] * equation['max'] + equation['c']) * 100) / 100;
+      const uH1 = Math.round((equation['a'] * uQ * uQ + equation['b'] * uQ + equation['c']) * 100) / 100;
+      if (uH1 >= uHMin && uH1 <= uHMax) {
+        uH.value = uH1;
+        isHaCross.value = true;
+      } else {
+        isHaCross.value = false;
+      }
+    }
+  }
+
+  function computeRLine() {
+    console.log('计算后的风量为------------>', uQ.value);
+    if (uH.value && uQ.value) {
+      const R = uH.value / Number(uQ.value) / Number(uQ.value);
+      const yAxis: number[] = [];
+      for (let i = 0; i < xData.length; i++) {
+        const x = xData[i];
+        const y = R * x * x;
+        if (x == uQ.value) {
+          uH.value = y;
+        }
+        yAxis.push(y);
+      }
+      const series = {
+        name: 'R',
+        type: 'line',
+        smooth: true,
+        showSymbol: false,
+        zlevel: 0,
+        emphasis: {
+          focus: 'series',
+        },
+        itemStyle: { normal: { label: { show: true } } },
+        lineStyle: {
+          width: 2,
+          color: '#D0A343',
+        },
+        endLabel: {
+          show: true,
+          formatter: '{a}',
+          distance: 0,
+          color: '#D0A343',
+        },
+        data: yAxis,
+      };
+      yDataList[lineNum] = series;
+    }
+  }
+
+  function reSetLine() {
+    let minIndex = -1;
+    for (let i = 0; i < yDataList.length; i++) {
+      if (i !== lineNum && i != lineNum + 1) {
+        if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['color'] = '#ffffff88';
+        if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['width'] = 1;
+        if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['color']) {
+          if (i % 5 == 0) {
+            yDataList[i]['endLabel']['color'] = '#39E9FE99';
+          } else {
+            yDataList[i]['endLabel']['color'] = '#39E9FE00';
+          }
+        }
+        if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['backgroundColor']) yDataList[i]['endLabel']['backgroundColor'] = 'transparent';
+        if (yDataList[i]['z']) yDataList[i]['z'] = 1;
+      }
+
+      if (resultObj.value && `${resultObj.value.Hz}Hz` == yDataList[i]['name']) {
+        minIndex = i;
+      }
+    }
+    if (minIndex != -1) {
+      yDataList[minIndex]['lineStyle']['color'] = '#9A60B4';
+      yDataList[minIndex]['lineStyle']['width'] = 2;
+      yDataList[minIndex]['endLabel']['color'] = '#9A60B4';
+      yDataList[minIndex]['endLabel']['backgroundColor'] = '#111';
+      yDataList[minIndex]['z'] = 999;
+    }
+  }
+
+  // 根据风量计算压差
+  function computePa() {
+    const R = uH.value / Number(uQ.value) / Number(uQ.value);
+    const pointX = Number(uQ.value);
+    const pointY = Number(uH.value);
+    type ItemType = {
+      x: number;
+      y: number;
+      Hz: number;
+    };
+    const paList = new Map<number, ItemType>(); // key 是最近距离
+    const getIntersectionPoint = (a, b, c, R, min, max) => {
+      const obj: { x: undefined | number; y: undefined | number; min: number; max: number } = { x: undefined, y: undefined, min: min, max: max };
+      // 计算二次方程的判别式
+      const discriminant = b * b - 4 * (a - R) * c;
+
+      if (discriminant > 0) {
+        // 有两个实根
+        const x1 = (-b + Math.sqrt(discriminant)) / (2 * (a - R));
+        const x2 = (-b - Math.sqrt(discriminant)) / (2 * (a - R));
+
+        const y1 = R * x1 * x1;
+        const y2 = R * x2 * x2;
+        if (x1 >= min && x1 <= max) {
+          obj.x = x1;
+          obj.y = y1;
+        } else {
+          obj.x = x2;
+          obj.y = y2;
+        }
+      } else if (discriminant === 0) {
+        // 有一个实根
+        const x = -b / (2 * (a - R));
+        const y = R * x * x;
+        if (x >= min && x <= max) {
+          obj.x = x;
+          obj.y = y;
+        }
+        // console.log(`唯一交点: (${x}, ${y})`);
+      } else {
+        // 没有实根,交点在虚数域
+        console.log('没有实数交点');
+        isHaCross.value = false;
+      }
+      return obj;
+    };
+
+    for (let key in assistanceData.value) {
+      const item: AssistanceItemType = assistanceData.value[key];
+      paList.set(item.Hz, getIntersectionPoint(item.a, item.b, item.c, R, item.min, item.max));
+    }
+
+    const min = (points: Map<number, ItemType>) => {
+      const targetX = uQ.value;
+      const targetY = uH.value;
+      let minDistance = Number.POSITIVE_INFINITY;
+      let closestPoint = null;
+      let keyVal = '';
+      // 遍历已知点数组,计算距离并更新最小距离和对应的点
+      for (const [key, point] of points) {
+        const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
+        if (distance < minDistance) {
+          minDistance = distance;
+          closestPoint = point;
+          keyVal = key;
+        }
+      }
+
+      if (closestPoint !== null) {
+        // console.log(`距离最小的点是 (${closestPoint.x}, ${closestPoint.y}), 距离为 ${minDistance}`);
+        if (closestPoint.x < closestPoint.min || closestPoint.x > closestPoint.max) {
+          resultObj.value = null;
+          isHaCross.value = false;
+          console.log('没有找到最小距离的点');
+        } else {
+          resultObj.value = { x: closestPoint.x, y: closestPoint.y, Hz: keyVal };
+          isHaCross.value = true;
+        }
+      } else {
+        resultObj.value = null;
+        isHaCross.value = false;
+        console.log('没有找到最小距离的点');
+      }
+    };
+    min(paList);
+  }
+
+  function computeR() {
+    if (uQ.value && uH.value) {
+      computeRLine();
+      computePa();
+      const x = resultObj.value && resultObj.value.x ? resultObj.value.x.toFixed(0) : -100;
+      const y = resultObj.value && resultObj.value.y ? Number(resultObj.value.y.toFixed(0)) : -100;
+      const series = {
+        type: 'effectScatter',
+        symbolSize: 5,
+        // symbolOffset:[1, 1],
+        showEffectOn: 'render',
+        // 涟漪特效相关配置。
+        rippleEffect: {
+          // 波纹的绘制方式,可选 'stroke' 和 'fill'。
+          brushType: 'stroke',
+        },
+        zlevel: 1,
+        z: 999,
+        itemStyle: {
+          color: '#C60000',
+        },
+        data: [[x, y]],
+      };
+      yDataList[lineNum + 1] = series;
+    }
+    // // 根据计算后的得到的频率,风量,瓦斯浓度
+    // getMonitor();
+  }
+
+  function getMonitor() {
+    clearTimeout(timer);
+    timer = undefined;
+    const n = 10;
+    const windQuantity = uQ1.value;
+    const obj = {
+      m3: windQuantity,
+      gas: gasWarningVal.value,
+      time: '',
+      Hz: uHz.value,
+    };
+    const monitorList: { m3: number; gas: number; Hz: number; time: string }[] = [];
+    for (let i = 0; i < n; i++) {
+      const item = cloneDeep(obj);
+      const m3Temp = (Math.random() * 2 - 1) * Math.random() * 20;
+      const gas = m3Temp * 0.0002;
+      item.time = dayjs(new Date().getTime() - (n + i) * 3000).format('HH:mm:ss');
+      item.m3 = (obj.m3 + m3Temp).toFixed(2);
+      item.gas = (obj.gas + gas).toFixed(4);
+      item.Hz = (obj.Hz + Math.random()).toFixed(2);
+      monitorList.unshift(item);
+    }
+    monitorData.value = cloneDeep(monitorList);
+
+    setTimeout(() => {
+      clearTimeout(timer);
+      timer = undefined;
+
+      timer = 0;
+      if (uQ1.value && uH.value && uQ.value) {
+        openTimer(cloneDeep(obj), 0);
+      } else {
+        openTimer(cloneDeep(obj), 0);
+      }
+    }, 1000);
+  }
+
+  function startCompute() {
+    setTimeout(() => {
+      message.success('指令下发成功!');
+      isStartCompute.value = 1;
+    }, 800);
+  }
+
+  function resetCompute() {
+    setTimeout(() => {
+      message.success('指令下发成功!');
+      isStartCompute.value = -1;
+      tempList.length = 0;
+      n = 0;
+    }, 800);
+  }
+
+  let timer = undefined;
+  let n = 0;
+  let tempList = [];
+  function openTimer(obj: { m3: number; gas: number; Hz: number; time: string }) {
+    // 打开定时器
+    const monitorList = cloneDeep(monitorData.value);
+    if (timer !== undefined) {
+      timer = setTimeout(() => {
+        obj.m3 = Number(obj.m3);
+        obj.gas = Number(obj.gas);
+        obj.Hz = Number(obj.Hz);
+        const item = cloneDeep(obj);
+        item.time = dayjs(new Date().getTime()).format('HH:mm:ss');
+        if (resultObj.value && resultObj.value.x && resultObj.value.y && isStartCompute.value != 0) {
+          if (isStartCompute.value == 1 && Number(obj.m3) > uQ.value && Number(obj.gas) < gasWarningMax.value) {
+            isStartCompute.value = 0;
+            n = 0;
+          } else if (isStartCompute.value == -1 && Number(obj.m3) < uQ1.value) {
+            isStartCompute.value = 0;
+            n = 0;
+          }
+        }
+
+        if (!isStartCompute.value) {
+          const m3Temp = (Math.random() * 2 - 1) * Math.random() * Math.random() * 10;
+          const gas = m3Temp * 0.0002;
+          item.m3 = (obj.m3 + m3Temp).toFixed(2);
+          item.gas = (obj.gas + gas).toFixed(4);
+          item.Hz = (obj.Hz + Math.random()).toFixed(2);
+          n = 0;
+        } else {
+          if (n < 2) {
+            const item1 = cloneDeep(obj);
+            const m3Temp = Math.random() * Math.random() * 10;
+            const gas = m3Temp * 0.0002;
+            item1.m3 = (obj.m3 + m3Temp).toFixed(2);
+            item1.gas = (obj.gas + gas).toFixed(4);
+            item1.Hz = (obj.Hz + (Math.random() * 2 - 1) * Math.random()).toFixed(2);
+            tempList.push(item1);
+          }
+
+          // 计算  uQ1 -> uQ  gas -> gasWarningMax.value Hz -> resultObj.value.Hz
+          if (isStartCompute.value == 1) {
+            if (resultObj.value.Hz - obj.Hz > 0) {
+              item.Hz = (uHz.value + (2 * n * (resultObj.value.Hz - uHz.value)) / 20).toFixed(2);
+              if (resultObj.value.Hz - obj.Hz < 0) {
+                item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
+              }
+            } else {
+              // item.Hz = (resultObj.value.Hz + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
+              item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
+            }
+            item.m3 = (obj.m3 + (0.017 * n * item.Hz * (item.Hz - uHz.value) * (uQ.value - uQ1.value)) / 600).toFixed(2);
+            if (Number(item.m3) > uQ.value) {
+              item.m3 = (uQ.value + Math.random() * 10).toFixed(2);
+            }
+            item.gas = (
+              gasWarningVal.value -
+              (0.015 * item.Hz * n * (item.Hz - uHz.value) * (gasWarningVal.value - gasWarningMax.value)) / 200
+            ).toFixed(4);
+          } else {
+            // 复位
+            if (obj.Hz - uHz.value > 0) {
+              item.Hz = (obj.Hz - (2 * n * (resultObj.value.Hz - uHz.value)) / 30).toFixed(2);
+              if (item.Hz - uHz.value < 0) {
+                item.Hz = uHz.value - 0.3;
+              }
+            } else {
+              item.Hz = (uHz.value + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
+            }
+            item.m3 = (obj.m3 - (0.02 * n * n * item.Hz * (resultObj.value.Hz - uHz.value) * (uQ.value - uQ1.value)) / 400).toFixed(2);
+            if (item.m3 < uQ1.value) {
+              item.m3 = uQ1.value - Math.random() * 10;
+            }
+            item.gas = (obj.gas + (0.015 * item.Hz * n * (uHz.value - item.Hz) * (gasWarningVal.value - gasWarningMax.value)) / 800).toFixed(4);
+          }
+        }
+        if (monitorList.length >= 10) {
+          monitorList.shift();
+          const monitor = cloneDeep(item);
+          const data = tempList.shift();
+          if (data) {
+            item['m3'] = data['m3'];
+            item['gas'] = data['gas'];
+          }
+          tempList.push(monitor);
+          monitorList.push(item);
+        } else {
+          monitorList.push(item);
+        }
+        monitorData.value = monitorList;
+        // console.log('瓦斯监测数据-------------->', monitorData.value);
+        if (timer) {
+          if (!isStartCompute.value) {
+            // n++;
+            openTimer(cloneDeep(obj));
+          } else {
+            n++;
+            openTimer(cloneDeep(item));
+          }
+        }
+      }, 3000);
+    }
+  }
+
+  function edit(flag) {
+    if (flag == 'info') {
+      formType.value = '编辑风机信息';
+    }
+    if (flag == 'line') {
+      formType.value = '编辑特性曲线';
+    }
+    if (formShow.value == true) {
+      formShow.value = false;
+      nextTick(() => {
+        formShow.value = true;
+      });
+    } else {
+      formShow.value = true;
+    }
+  }
+
+  function onSubmit() {
+    emit('close');
+    closeModal();
+    ChartRef.value = null;
+    uQ.value = undefined;
+    uH.value = undefined;
+    formType.value = '';
+    refresh.value = true;
+    xData.length = 0;
+    yDataList.length = 0;
+    lineNum = 0;
+    lineEquation.value = [];
+    resultObj.value = null;
+    monitorData.value = [];
+    clearTimeout(timer);
+    timer = undefined;
+  }
+
+  async function onCancel() {
+    return new Promise((resolve) => {
+      if (isStartCompute.value == 0) {
+        onSubmit();
+        resolve(true);
+      } else {
+        message.warning('为保障矿井安全生产,请确保已复位!!!');
+        resolve(false);
+      }
+    });
+  }
+
+  function initEcharts() {
+    if (ChartRef.value) {
+      reSetLine();
+      myChart.value = echarts.init(ChartRef.value);
+      option && myChart.value.setOption(option);
+      refresh.value = false;
+      getMonitor();
+      nextTick(() => {
+        setTimeout(() => {
+          refresh.value = true;
+        }, 0);
+      });
+    }
+  }
+
+  function makeLine() {
+    if (uQ.value && uH.value) {
+      loadding.value = true;
+      setTimeout(() => {
+        computeR();
+        reSetLine();
+        option && myChart.value.setOption(option);
+        loadding.value = false;
+      }, 1200);
+    }
+  }
+  function handleSubmit() {
+    message.success('提交成功');
+    setTimeout(() => {
+      formShow.value = false;
+    }, 800);
+  }
+  onMounted(() => {
+    timer = undefined;
+  });
+</script>
+
+<style scoped lang="less">
+  .modal-box {
+    display: flex;
+    flex-direction: row;
+    background-color: #ffffff05;
+    padding: 20px 8px;
+    border: 1px solid #00d8ff22;
+    position: relative;
+    // min-height: 600px;
+    .box-title {
+      width: calc(100% - 40px);
+      text-align: center;
+      background-color: #1dc1f522;
+    }
+    .info-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 2px 0px;
+      margin: 4px 0;
+      background-image: linear-gradient(to right, #39deff15, #3977e500);
+      &:first-child {
+        margin-top: 0;
+      }
+      .title {
+        width: 200px;
+        text-align: left;
+        padding-left: 20px;
+        color: #f1f1f1cc;
+      }
+      .value {
+        width: 150px;
+        color: #00d8ff;
+        padding-right: 20px;
+        text-align: right;
+      }
+    }
+    .right-box {
+      width: 320px;
+      .info-lines {
+        width: calc(100% - 2px);
+        height: 450px;
+        box-shadow: 0px 0px 50px #86baff08 inset;
+        overflow-y: auto;
+        margin-top: 5px;
+        .title {
+          width: 100%;
+          color: #f1f1f1cc;
+        }
+      }
+    }
+    .center-box {
+      flex: 1;
+      margin: 0 10px;
+      display: flex;
+      .info-echarts {
+        // background-color: #ffffff11;
+      }
+      .result-tip {
+        text-align: center;
+        background-color: #00000011;
+        line-height: 28px;
+        margin: 10px 50px 0 50px;
+        border: 1px solid #00d8ff22;
+        border-radius: 2px;
+      }
+    }
+    .tip-box {
+      width: 1040px;
+      height: 44px;
+      position: absolute;
+      top: 447px;
+      display: flex;
+      padding: 0 20px;
+      .title {
+        width: 142px;
+        height: 43px;
+        display: flex;
+        align-items: center;
+        padding-left: 30px;
+        background-image: url('@/assets/images/fanlocal-tip/tip-title.png');
+        position: relative;
+        &::before {
+          content: '';
+          display: inline-block;
+          position: absolute;
+          width: 31px;
+          height: 31px;
+          top: 5px;
+          left: -8px;
+          background-image: url('@/assets/images/fanlocal-tip/tip-icon.png');
+        }
+      }
+      .tip-container {
+        width: 898px;
+        height: 44px;
+        line-height: 44px;
+        display: flex;
+        background-image: url('@/assets/images/fanlocal-tip/tip-bg.png');
+        background-size: cover;
+      }
+    }
+  }
+  .setting-box {
+    width: 1170px;
+    height: 70px;
+    margin: 10px 0;
+    background-color: #ffffff05;
+    border: 1px solid #00d8ff22;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+
+    .right-inputs {
+      width: 100%;
+      display: flex;
+      height: 40px;
+      margin: 0 10px;
+      justify-content: space-between;
+    }
+    .left-buttons {
+      display: flex;
+      height: 40px;
+
+      .btn {
+        margin: 0 10px;
+      }
+    }
+    .border-clip {
+      width: 1px;
+      height: 25px;
+      border-right: 1px solid #8b8b8b77;
+    }
+    .input-title {
+      max-width: 150px;
+    }
+    .input-box {
+      width: 220px !important;
+      background: transparent !important;
+      border-color: #00d8ff44 !important;
+      margin-right: 20px;
+      color: #fff !important;
+    }
+    .btn {
+      padding: 8px 20px;
+      position: relative;
+      border-radius: 2px;
+      color: #fff;
+      width: fit-content;
+      cursor: pointer;
+
+      &::before {
+        position: absolute;
+        display: block;
+        content: '';
+        width: calc(100% - 4px);
+        height: calc(100% - 4px);
+        top: 2px;
+        left: 2px;
+        border-radius: 2px;
+        z-index: -1;
+      }
+    }
+
+    .btn1 {
+      border: 1px solid #5cfaff;
+
+      &::before {
+        background-image: linear-gradient(#2effee92, #0cb1d592);
+      }
+
+      &:hover {
+        border: 1px solid #5cfaffaa;
+
+        &::before {
+          background-image: linear-gradient(#2effee72, #0cb1d572);
+        }
+      }
+    }
+  }
+  .is-open {
+    animation: open 0.5s;
+    animation-iteration-count: 1;
+    animation-fill-mode: forwards;
+    animation-timing-function: ease-in;
+  }
+  .is-close {
+    height: 0px;
+  }
+
+  @keyframes open {
+    0% {
+      height: 0px;
+    }
+    100% {
+      height: fit-content;
+    }
+  }
+
+  @keyframes close {
+    0% {
+      height: fit-content;
+    }
+    100% {
+      height: 0px;
+    }
+  }
+  :deep(.zxm-divider-inner-text) {
+    color: #cacaca88 !important;
+  }
+  :deep(.zxm-form-item) {
+    margin-bottom: 10px;
+  }
+</style>

+ 941 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/conditionAssistance1.vue

@@ -0,0 +1,941 @@
+<template>
+  <BasicModal
+    @register="register"
+    title="局部通风机运行工况智能决策"
+    :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }"
+    :width="isComputeGas ? '1400px' : '950px'"
+    v-bind="$attrs"
+    @ok="onSubmit"
+    :closeFunc="onCancel"
+    :canFullscreen="false"
+    :destroyOnClose="true"
+    :footer="null"
+    :maskClosable="false"
+  >
+    <div class="modal-box">
+      <div v-if="isComputeGas" class="left-box" style="width: 550px; height: 400px">
+        <BarAndLine
+          class="echarts-line"
+          xAxisPropType="time"
+          :dataSource="monitorData"
+          height="400px"
+          :chartsColumns="chartsColumnList"
+          :option="echatsOption"
+          chartsType="listMonitor"
+        />
+      </div>
+      <div class="center-box">
+        <a-spin :spinning="loadding" tip="正在计算,请稍等。。。">
+          <div ref="ChartRef" class="info-echarts" :style="{ width: isComputeGas ? '450px' : '520px', height: '400px' }"></div>
+        </a-spin>
+      </div>
+      <div class="right-box">
+        <!-- <div class="box-title">曲线方程</div> -->
+        <dv-decoration7 style="height: 20px">
+          <div class="box-title">曲线方程</div>
+        </dv-decoration7>
+        <div class="info-lines">
+          <div v-for="(item, index) in lineEquation" class="info-item" :key="index">
+            <div class="title">{{ item }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="tip-box">
+        <div class="title">最佳工况点 <SendOutlined class="ml-5px" /></div>
+        <div class="tip-container" :style="{ width: isComputeGas ? '898px' : '400px' }">
+          <template v-if="resultObj && isHaCross">
+            <div class="ml-10px">
+              <span>频率:</span>
+              <span style="color: #d066ff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.Hz) }}Hz</span>
+            </div>
+            <div class="ml-10px">
+              <span>风量:</span>
+              <span style="color: #3adeff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.x) }} m³/min</span>
+            </div>
+            <div class="ml-10px">
+              <span>负压</span>
+              <span style="color: #ffbe34; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.y) }} Pa</span>
+            </div>
+          </template>
+          <div v-else-if="isHaCross" class="ml-10px">暂无</div>
+          <div v-else style="color: #ffbe34; padding: 0 10px; font-weight: 600" class="ml-10px">无有效工况点</div>
+        </div>
+      </div>
+    </div>
+    <div class="setting-box">
+      <div class="right-inputs">
+        <div class="vent-flex-row">
+          <div class="input-title">风量(m³/min):</div>
+          <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uQ1" />
+          <div class="input-title">风压(Pa):</div>
+          <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uH" />
+          <div v-if="!isComputeGas" class="btn btn1" @click="makeLine">决策工况</div>
+          <template v-else>
+            <div class="btn btn1" @click="startCompute">一键调控</div>
+            <div class="btn btn1" @click="resetCompute">一键复位</div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+  //ts语法
+  import { ref, onMounted, reactive, nextTick, computed } from 'vue';
+  import echarts from '/@/utils/lib/echarts';
+  import { option, initData, fanInfoData, chartsColumnList, echatsOption } from '../fanLocal.data';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { useForm } from '/@/components/Form/index';
+  import { Input, InputNumber } from 'ant-design-vue';
+  import { Decoration7 as DvDecoration7 } from '@kjgl77/datav-vue3';
+  import { message } from 'ant-design-vue';
+  import { formatNum } from '/@/utils/ventutil';
+  import BarAndLine from '/@/components/chart/BarAndLine.vue';
+  import { cloneDeep } from 'lodash-es';
+  import dayjs from 'dayjs';
+  import { SendOutlined } from '@ant-design/icons-vue';
+
+  const emit = defineEmits(['close', 'register', 'openModal']);
+  const props = defineProps({
+    dataSource: {
+      type: Array,
+      default: () => [],
+    },
+    frequency: {
+      type: Number,
+      default: 30,
+    },
+    m3: {
+      type: Number,
+      default: 670.8,
+    },
+    // gasWarningMax: { type: Number, default: 0.5 },
+    // gasWarningVal: { type: Number, default: 0.6 },
+    // windQuantity: { type: Number, default: 635.84 },
+  });
+  type AssistanceItemType = {
+    angle: number;
+    Hz: number;
+    a: number;
+    b: number;
+    c: number;
+    min: number;
+    max: number;
+  };
+
+  // 注册 modal
+  const [register, { closeModal }] = useModalInner((data) => {
+    nextTick(() => {
+      computeAssistance();
+      if (option['xAxis']) option['xAxis']['data'] = xData;
+      option['series'] = yDataList;
+      if (JSON.stringify(data) !== '{}') {
+        uQ1.value = Number(data['m3']);
+        uHz.value = Math.ceil(data['frequency']);
+        gasWarningVal.value = data['gasWarningVal'];
+        isComputeGas.value = true;
+        nextTick(() => {
+          computeUH(data['frequency'], data['m3']);
+          initEcharts();
+          setTimeout(() => {
+            // 根据频率计算uH
+            makeLine();
+          }, 2000);
+        });
+      } else {
+        initEcharts();
+        isComputeGas.value = false;
+      }
+    });
+  });
+  const loadding = ref<boolean>(false);
+  const formShow = ref(false);
+  const formType = ref('');
+  const ChartRef = ref();
+  const myChart = ref();
+  const refresh = ref(true);
+  const xDataMax = 1000;
+  let xDataMin = 0;
+  const xData: any[] = [];
+  const yDataList: [] = [];
+  let lineNum = 0;
+  const lineEquation = ref<string[]>([]);
+  const assistanceData = ref([]);
+  const monitorData = ref([]);
+  const gasWarningVal = ref(0);
+  const gasWarningMax = ref(0.5);
+  const isComputeGas = ref(false);
+  const isStartCompute = ref(0);
+  const uHz = ref(0);
+  const uQ1 = ref(0);
+  const uQ = computed(() => {
+    if (uQ1.value) {
+      if (gasWarningVal.value) {
+        return ((uQ1.value * gasWarningVal.value) / gasWarningMax.value) * 1.08;
+      }
+      return uQ1.value;
+    } else {
+      return 0;
+    }
+  });
+  const uH = ref<number | undefined>(undefined); //  - 1000
+  const isHaCross = ref(true);
+  const resultObj = ref<{ x: number; y: number; Hz: number } | null>(null);
+
+  const [registerForm, {}] = useForm({
+    labelWidth: 120,
+    actionColOptions: {
+      span: 24,
+    },
+    compact: true,
+    showSubmitButton: true,
+    submitButtonOptions: {
+      text: '提交',
+      preIcon: '',
+    },
+    showResetButton: true,
+    resetButtonOptions: {
+      text: '关闭',
+      preIcon: '',
+    },
+    resetFunc: async () => {
+      formShow.value = false;
+    },
+  });
+
+  function computeAssistance() {
+    assistanceData.value = initData();
+    lineNum = 0;
+    const assistanceDataList = [];
+    const lineEquationList: string[] = [];
+    for (const key in assistanceData.value) {
+      const item = assistanceData.value[key];
+      assistanceDataList.push(item);
+      lineEquationList.push(
+        `H${parseInt(item['Hz'])} = ${item['a']}Q² ${Number(item['b']) > 0 ? '+' : '-'} ${Math.abs(Number(item['b'])).toFixed(4)}Q ${
+          Number(item['c']) > 0 ? '+' : '-'
+        } ${Math.abs(Number(item['c'])).toFixed(4)}`
+      );
+    }
+    lineEquation.value = lineEquationList;
+    lineNum = assistanceDataList.length;
+    xDataMin =
+      Math.min.apply(
+        Math,
+        assistanceDataList.map((item) => {
+          return item.min;
+        })
+      ) - 100;
+    // const xDataMax = Math.max.apply(Math, assistanceDataList.map(item => { return item.max }))
+    fanInfoData.flfw = `${xDataMin}~${xDataMax}`;
+    const computeItem = (item: AssistanceItemType) => {
+      const min = item.min;
+      const max = item.max;
+      const HList: number[] = [];
+      for (let i = xDataMin; i <= xDataMax; i++) {
+        if (i < min) {
+          HList.push(null);
+        } else if (i > max) {
+          HList.push(null);
+        } else {
+          HList.push(item.a * i * i + item.b * i + item.c);
+        }
+      }
+      return HList;
+    };
+
+    for (const key in assistanceData.value) {
+      const element: AssistanceItemType = assistanceData.value[key];
+      const yData: number[] = computeItem(element);
+      const series = {
+        type: 'line',
+        name: `${element['Hz']}Hz`,
+        smooth: true,
+        showSymbol: false,
+        symbol: 'none',
+        emphasis: {
+          focus: 'series',
+        },
+        itemStyle: { normal: { label: { show: true } } },
+        lineStyle: {
+          width: 1,
+          color: '#ffffff88',
+        },
+        zlevel: 0,
+        z: 1,
+        endLabel: {
+          show: true,
+          formatter: '{a}',
+          distance: 0,
+          color: '#39E9FE99',
+          backgroundColor: 'transparent',
+          padding: [3, 3, 2, 3],
+        },
+        data: yData,
+      };
+
+      yDataList.push(series);
+    }
+
+    for (let i = xDataMin; i <= xDataMax; i++) {
+      xData.push(i);
+    }
+  }
+
+  function computeUH(Hz: number, uQ: number) {
+    debugger;
+    const equation = assistanceData.value.find((item) => {
+      return Math.ceil(Hz) == item['Hz'];
+    });
+    if (equation) {
+      const uHMax = Math.round((equation['a'] * equation['min'] * equation['min'] + equation['b'] * equation['min'] + equation['c']) * 100) / 100;
+      const uHMin = Math.round((equation['a'] * equation['max'] * equation['max'] + equation['b'] * equation['max'] + equation['c']) * 100) / 100;
+      const uH1 = Math.round((equation['a'] * uQ * uQ + equation['b'] * uQ + equation['c']) * 100) / 100;
+      if (uH1 >= uHMin && uH1 <= uHMax) {
+        uH.value = uH1;
+        isHaCross.value = true;
+      } else {
+        isHaCross.value = false;
+      }
+    }
+  }
+
+  function computeRLine() {
+    console.log('计算后的风量为------------>', uQ.value);
+    if (uH.value && uQ.value) {
+      const R = uH.value / Number(uQ.value) / Number(uQ.value);
+      const yAxis: number[] = [];
+      for (let i = 0; i < xData.length; i++) {
+        const x = xData[i];
+        const y = R * x * x;
+        if (x == uQ.value) {
+          uH.value = y;
+        }
+        yAxis.push(y);
+      }
+      const series = {
+        name: 'R',
+        type: 'line',
+        smooth: true,
+        showSymbol: false,
+        zlevel: 0,
+        emphasis: {
+          focus: 'series',
+        },
+        itemStyle: { normal: { label: { show: true } } },
+        lineStyle: {
+          width: 2,
+          color: '#D0A343',
+        },
+        endLabel: {
+          show: true,
+          formatter: '{a}',
+          distance: 0,
+          color: '#D0A343',
+        },
+        data: yAxis,
+      };
+      yDataList[lineNum] = series;
+    }
+  }
+
+  function reSetLine() {
+    let minIndex = -1;
+    for (let i = 0; i < yDataList.length; i++) {
+      if (i !== lineNum && i != lineNum + 1) {
+        if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['color'] = '#ffffff88';
+        if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['width'] = 1;
+        if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['color']) {
+          yDataList[i]['endLabel']['color'] = '#39E9FE99';
+        }
+        if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['backgroundColor']) yDataList[i]['endLabel']['backgroundColor'] = 'transparent';
+        if (yDataList[i]['z']) yDataList[i]['z'] = 1;
+      }
+
+      if (resultObj.value && `${resultObj.value.Hz}Hz` == yDataList[i]['name']) {
+        minIndex = i;
+      }
+    }
+    if (minIndex != -1) {
+      yDataList[minIndex]['lineStyle']['color'] = '#9A60B4';
+      yDataList[minIndex]['lineStyle']['width'] = 2;
+      yDataList[minIndex]['endLabel']['color'] = '#9A60B4';
+      yDataList[minIndex]['endLabel']['backgroundColor'] = '#111';
+      yDataList[minIndex]['z'] = 999;
+    }
+  }
+
+  // 根据风量计算压差
+  function computePa() {
+    debugger;
+    const R = uH.value / Number(uQ.value) / Number(uQ.value);
+    const pointX = Number(uQ.value);
+    const pointY = Number(uH.value);
+    type ItemType = {
+      x: number;
+      y: number;
+      Hz: number;
+    };
+    const paList = new Map<number, ItemType>(); // key 是最近距离
+    const getIntersectionPoint = (a, b, c, R, min, max) => {
+      const obj: { x: undefined | number; y: undefined | number; min: number; max: number } = { x: undefined, y: undefined, min: min, max: max };
+      // 计算二次方程的判别式
+      const discriminant = b * b - 4 * (a - R) * c;
+
+      if (discriminant > 0) {
+        // 有两个实根
+        const x1 = (-b + Math.sqrt(discriminant)) / (2 * (a - R));
+        const x2 = (-b - Math.sqrt(discriminant)) / (2 * (a - R));
+
+        const y1 = R * x1 * x1;
+        const y2 = R * x2 * x2;
+        if (x1 >= min && x1 <= max) {
+          obj.x = x1;
+          obj.y = y1;
+        } else {
+          obj.x = x2;
+          obj.y = y2;
+        }
+      } else if (discriminant === 0) {
+        // 有一个实根
+        const x = -b / (2 * (a - R));
+        const y = R * x * x;
+        if (x >= min && x <= max) {
+          obj.x = x;
+          obj.y = y;
+        }
+        // console.log(`唯一交点: (${x}, ${y})`);
+      } else {
+        // 没有实根,交点在虚数域
+        console.log('没有实数交点');
+        isHaCross.value = false;
+      }
+      return obj;
+    };
+
+    for (let key in assistanceData.value) {
+      const item: AssistanceItemType = assistanceData.value[key];
+      paList.set(item.Hz, getIntersectionPoint(item.a, item.b, item.c, R, item.min, item.max));
+    }
+
+    const min = (points: Map<number, ItemType>) => {
+      const targetX = uQ.value;
+      const targetY = uH.value;
+      let minDistance = Number.POSITIVE_INFINITY;
+      let closestPoint = null;
+      let keyVal = '';
+      // 遍历已知点数组,计算距离并更新最小距离和对应的点
+      for (const [key, point] of points) {
+        const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
+        if (distance < minDistance) {
+          minDistance = distance;
+          closestPoint = point;
+          keyVal = key;
+        }
+      }
+
+      if (closestPoint !== null) {
+        // console.log(`距离最小的点是 (${closestPoint.x}, ${closestPoint.y}), 距离为 ${minDistance}`);
+        if (closestPoint.x < closestPoint.min || closestPoint.x > closestPoint.max) {
+          resultObj.value = null;
+          isHaCross.value = false;
+          console.log('没有找到最小距离的点');
+        } else {
+          resultObj.value = { x: closestPoint.x, y: closestPoint.y, Hz: keyVal };
+          isHaCross.value = true;
+        }
+      } else {
+        resultObj.value = null;
+        isHaCross.value = false;
+        console.log('没有找到最小距离的点');
+      }
+    };
+    min(paList);
+  }
+
+  function computeR() {
+    if (uQ.value && uH.value) {
+      computeRLine();
+      computePa();
+      const x = resultObj.value && resultObj.value.x ? resultObj.value.x.toFixed(0) : -100;
+      const y = resultObj.value && resultObj.value.y ? Number(resultObj.value.y.toFixed(0)) : -100;
+      const series = {
+        type: 'effectScatter',
+        symbolSize: 5,
+        // symbolOffset:[1, 1],
+        showEffectOn: 'render',
+        // 涟漪特效相关配置。
+        rippleEffect: {
+          // 波纹的绘制方式,可选 'stroke' 和 'fill'。
+          brushType: 'stroke',
+        },
+        zlevel: 1,
+        z: 999,
+        itemStyle: {
+          color: '#C60000',
+        },
+        data: [[x, y]],
+      };
+      yDataList[lineNum + 1] = series;
+    }
+    // // 根据计算后的得到的频率,风量,瓦斯浓度
+    // getMonitor();
+  }
+
+  function getMonitor() {
+    clearTimeout(timer);
+    timer = undefined;
+    const n = 10;
+    const windQuantity = uQ1.value;
+    const obj = {
+      m3: windQuantity,
+      gas: gasWarningVal.value,
+      time: '',
+      Hz: uHz.value,
+    };
+    const monitorList: { m3: number; gas: number; Hz: number; time: string }[] = [];
+    for (let i = 0; i < n; i++) {
+      const item = cloneDeep(obj);
+      const m3Temp = (Math.random() * 2 - 1) * Math.random() * 20;
+      const gas = m3Temp * 0.0002;
+      item.time = dayjs(new Date().getTime() - (n + i) * 3000).format('HH:mm:ss');
+      item.m3 = (obj.m3 + m3Temp).toFixed(2);
+      item.gas = (obj.gas + gas).toFixed(4);
+      item.Hz = (obj.Hz + Math.random()).toFixed(2);
+      monitorList.unshift(item);
+    }
+    monitorData.value = cloneDeep(monitorList);
+
+    setTimeout(() => {
+      clearTimeout(timer);
+      timer = undefined;
+
+      timer = 0;
+      if (uQ1.value && uH.value && uQ.value) {
+        openTimer(cloneDeep(obj), 0);
+      } else {
+        openTimer(cloneDeep(obj), 0);
+      }
+    }, 1000);
+  }
+
+  function startCompute() {
+    setTimeout(() => {
+      message.success('指令下发成功!');
+      isStartCompute.value = 1;
+    }, 800);
+  }
+
+  function resetCompute() {
+    setTimeout(() => {
+      message.success('指令下发成功!');
+      isStartCompute.value = -1;
+      tempList.length = 0;
+      n = 0;
+    }, 800);
+  }
+
+  let timer = undefined;
+  let n = 0;
+  let tempList = [];
+  function openTimer(obj: { m3: number; gas: number; Hz: number; time: string }) {
+    // 打开定时器
+    const monitorList = cloneDeep(monitorData.value);
+    if (timer !== undefined) {
+      timer = setTimeout(() => {
+        obj.m3 = Number(obj.m3);
+        obj.gas = Number(obj.gas);
+        obj.Hz = Number(obj.Hz);
+        const item = cloneDeep(obj);
+        item.time = dayjs(new Date().getTime()).format('HH:mm:ss');
+        if (resultObj.value && resultObj.value.x && resultObj.value.y && isStartCompute.value != 0) {
+          if (isStartCompute.value == 1 && Number(obj.m3) > uQ.value && Number(obj.gas) < gasWarningMax.value) {
+            isStartCompute.value = 0;
+            n = 0;
+          } else if (isStartCompute.value == -1 && Number(obj.m3) < uQ1.value) {
+            isStartCompute.value = 0;
+            n = 0;
+          }
+        }
+
+        if (!isStartCompute.value) {
+          const m3Temp = (Math.random() * 2 - 1) * Math.random() * Math.random() * 10;
+          const gas = m3Temp * 0.0002;
+          item.m3 = (obj.m3 + m3Temp).toFixed(2);
+          item.gas = (obj.gas + gas).toFixed(4);
+          item.Hz = (obj.Hz + Math.random()).toFixed(2);
+          n = 0;
+        } else {
+          if (n < 2) {
+            const item1 = cloneDeep(obj);
+            const m3Temp = Math.random() * Math.random() * 10;
+            const gas = m3Temp * 0.0002;
+            item1.m3 = (obj.m3 + m3Temp).toFixed(2);
+            item1.gas = (obj.gas + gas).toFixed(4);
+            item1.Hz = (obj.Hz + (Math.random() * 2 - 1) * Math.random()).toFixed(2);
+            tempList.push(item1);
+          }
+
+          // 计算  uQ1 -> uQ  gas -> gasWarningMax.value Hz -> resultObj.value.Hz
+          if (isStartCompute.value == 1) {
+            if (resultObj.value.Hz - obj.Hz > 0) {
+              item.Hz = (uHz.value + (2 * n * (resultObj.value.Hz - uHz.value)) / 20).toFixed(2);
+              if (resultObj.value.Hz - obj.Hz < 0) {
+                item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
+              }
+            } else {
+              // item.Hz = (resultObj.value.Hz + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
+              item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
+            }
+            item.m3 = (obj.m3 + (0.027 * n * item.Hz * (item.Hz - uHz.value) * (uQ.value - uQ1.value)) / 600).toFixed(2);
+            if (Number(item.m3) > uQ.value) {
+              item.m3 = (uQ.value + Math.random() * 10).toFixed(2);
+            }
+            item.gas = (
+              gasWarningVal.value -
+              (0.015 * item.Hz * n * (item.Hz - uHz.value) * (gasWarningVal.value - gasWarningMax.value)) / 200
+            ).toFixed(4);
+          } else {
+            // 复位
+            if (obj.Hz - uHz.value > 0) {
+              item.Hz = (obj.Hz - (2 * n * (resultObj.value.Hz - uHz.value)) / 30).toFixed(2);
+              if (item.Hz - uHz.value < 0) {
+                item.Hz = uHz.value - 0.3;
+              }
+            } else {
+              item.Hz = (uHz.value + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
+            }
+            item.m3 = (obj.m3 - (0.02 * n * n * item.Hz * (resultObj.value.Hz - uHz.value) * (uQ.value - uQ1.value)) / 400).toFixed(2);
+            if (item.m3 < uQ1.value) {
+              item.m3 = uQ1.value - Math.random() * 10;
+            }
+            item.gas = (obj.gas + (0.015 * item.Hz * n * (uHz.value - item.Hz) * (gasWarningVal.value - gasWarningMax.value)) / 800).toFixed(4);
+          }
+        }
+        if (monitorList.length >= 10) {
+          monitorList.shift();
+          const monitor = cloneDeep(item);
+          const data = tempList.shift();
+          if (data) {
+            item['m3'] = data['m3'];
+            item['gas'] = data['gas'];
+          }
+          tempList.push(monitor);
+          monitorList.push(item);
+        } else {
+          monitorList.push(item);
+        }
+        monitorData.value = monitorList;
+        // console.log('瓦斯监测数据-------------->', monitorData.value);
+        if (timer) {
+          if (!isStartCompute.value) {
+            // n++;
+            openTimer(cloneDeep(obj));
+          } else {
+            n++;
+            openTimer(cloneDeep(item));
+          }
+        }
+      }, 3000);
+    }
+  }
+
+  function edit(flag) {
+    if (flag == 'info') {
+      formType.value = '编辑风机信息';
+    }
+    if (flag == 'line') {
+      formType.value = '编辑特性曲线';
+    }
+    if (formShow.value == true) {
+      formShow.value = false;
+      nextTick(() => {
+        formShow.value = true;
+      });
+    } else {
+      formShow.value = true;
+    }
+  }
+
+  function onSubmit() {
+    emit('close');
+    closeModal();
+    ChartRef.value = null;
+    uQ.value = undefined;
+    uH.value = undefined;
+    formType.value = '';
+    refresh.value = true;
+    xData.length = 0;
+    yDataList.length = 0;
+    lineNum = 0;
+    lineEquation.value = [];
+    resultObj.value = null;
+    monitorData.value = [];
+    clearTimeout(timer);
+    timer = undefined;
+  }
+
+  async function onCancel() {
+    return new Promise((resolve) => {
+      if (isStartCompute.value == 0) {
+        onSubmit();
+        resolve(true);
+      } else {
+        message.warning('为保障矿井安全生产,请确保已复位!!!');
+        resolve(false);
+      }
+    });
+  }
+
+  function initEcharts() {
+    if (ChartRef.value) {
+      reSetLine();
+      myChart.value = echarts.init(ChartRef.value);
+      option && myChart.value.setOption(option);
+      refresh.value = false;
+      getMonitor();
+      nextTick(() => {
+        setTimeout(() => {
+          refresh.value = true;
+        }, 0);
+      });
+    }
+  }
+
+  function makeLine() {
+    if (uQ.value && uH.value) {
+      loadding.value = true;
+      setTimeout(() => {
+        computeR();
+        reSetLine();
+        option && myChart.value.setOption(option);
+        loadding.value = false;
+      }, 1200);
+    }
+  }
+  function handleSubmit() {
+    message.success('提交成功');
+    setTimeout(() => {
+      formShow.value = false;
+    }, 800);
+  }
+  onMounted(() => {
+    timer = undefined;
+  });
+</script>
+
+<style scoped lang="less">
+  .modal-box {
+    display: flex;
+    flex-direction: row;
+    background-color: #ffffff05;
+    padding: 20px 8px;
+    border: 1px solid #00d8ff22;
+    position: relative;
+    // min-height: 600px;
+    .box-title {
+      width: calc(100% - 40px);
+      text-align: center;
+      background-color: #1dc1f522;
+    }
+    .info-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 2px 0px;
+      margin: 4px 0;
+      background-image: linear-gradient(to right, #39deff15, #3977e500);
+      &:first-child {
+        margin-top: 0;
+      }
+      .title {
+        width: 200px;
+        text-align: left;
+        padding-left: 20px;
+        color: #f1f1f1cc;
+      }
+      .value {
+        width: 150px;
+        color: #00d8ff;
+        padding-right: 20px;
+        text-align: right;
+      }
+    }
+    .right-box {
+      width: 320px;
+      .info-lines {
+        width: calc(100% - 2px);
+        height: 450px;
+        box-shadow: 0px 0px 50px #86baff08 inset;
+        overflow-y: auto;
+        margin-top: 5px;
+        .title {
+          width: 100%;
+          color: #f1f1f1cc;
+        }
+      }
+    }
+    .center-box {
+      flex: 1;
+      margin: 0 10px;
+      display: flex;
+      .info-echarts {
+        // background-color: #ffffff11;
+      }
+      .result-tip {
+        text-align: center;
+        background-color: #00000011;
+        line-height: 28px;
+        margin: 10px 50px 0 50px;
+        border: 1px solid #00d8ff22;
+        border-radius: 2px;
+      }
+    }
+    .tip-box {
+      width: 1040px;
+      height: 44px;
+      position: absolute;
+      top: 447px;
+      display: flex;
+      padding: 0 20px;
+      .title {
+        width: 142px;
+        height: 43px;
+        display: flex;
+        align-items: center;
+        padding-left: 30px;
+        background-image: url('@/assets/images/fanlocal-tip/tip-title.png');
+        position: relative;
+        &::before {
+          content: '';
+          display: inline-block;
+          position: absolute;
+          width: 31px;
+          height: 31px;
+          top: 5px;
+          left: -8px;
+          background-image: url('@/assets/images/fanlocal-tip/tip-icon.png');
+        }
+      }
+      .tip-container {
+        width: 898px;
+        height: 44px;
+        line-height: 44px;
+        display: flex;
+        background-image: url('@/assets/images/fanlocal-tip/tip-bg.png');
+        background-size: cover;
+      }
+    }
+  }
+  .setting-box {
+    width: 1170px;
+    height: 70px;
+    margin: 10px 0;
+    background-color: #ffffff05;
+    border: 1px solid #00d8ff22;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+
+    .right-inputs {
+      width: 100%;
+      display: flex;
+      height: 40px;
+      margin: 0 10px;
+      justify-content: space-between;
+    }
+    .left-buttons {
+      display: flex;
+      height: 40px;
+
+      .btn {
+        margin: 0 10px;
+      }
+    }
+    .border-clip {
+      width: 1px;
+      height: 25px;
+      border-right: 1px solid #8b8b8b77;
+    }
+    .input-title {
+      max-width: 150px;
+    }
+    .input-box {
+      width: 220px !important;
+      background: transparent !important;
+      border-color: #00d8ff44 !important;
+      margin-right: 20px;
+      color: #fff !important;
+    }
+    .btn {
+      padding: 8px 20px;
+      position: relative;
+      border-radius: 2px;
+      color: #fff;
+      width: fit-content;
+      cursor: pointer;
+
+      &::before {
+        position: absolute;
+        display: block;
+        content: '';
+        width: calc(100% - 4px);
+        height: calc(100% - 4px);
+        top: 2px;
+        left: 2px;
+        border-radius: 2px;
+        z-index: -1;
+      }
+    }
+
+    .btn1 {
+      border: 1px solid #5cfaff;
+
+      &::before {
+        background-image: linear-gradient(#2effee92, #0cb1d592);
+      }
+
+      &:hover {
+        border: 1px solid #5cfaffaa;
+
+        &::before {
+          background-image: linear-gradient(#2effee72, #0cb1d572);
+        }
+      }
+    }
+  }
+  .is-open {
+    animation: open 0.5s;
+    animation-iteration-count: 1;
+    animation-fill-mode: forwards;
+    animation-timing-function: ease-in;
+  }
+  .is-close {
+    height: 0px;
+  }
+
+  @keyframes open {
+    0% {
+      height: 0px;
+    }
+    100% {
+      height: fit-content;
+    }
+  }
+
+  @keyframes close {
+    0% {
+      height: fit-content;
+    }
+    100% {
+      height: 0px;
+    }
+  }
+  :deep(.zxm-divider-inner-text) {
+    color: #cacaca88 !important;
+  }
+  :deep(.zxm-form-item) {
+    margin-bottom: 10px;
+  }
+</style>

+ 54 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-echart-line.vue

@@ -0,0 +1,54 @@
+<template>
+    <div class="alarm-history">
+        <BarAndLine class="echarts-line" xAxisPropType="time" :dataSource="historyLists" height="90%" width="100%"
+            :chartsColumns="chartsColumn" :option="echatsOption" chartsType="listMonitor" />
+    </div>
+</template>
+<script setup lang="ts">
+import { onBeforeMount, ref, watch, onMounted, nextTick, defineAsyncComponent, reactive, onUnmounted, inject, unref } from 'vue';
+import BarAndLine from '../../../../../components/chart/BarAndLine.vue';
+import { echatsOption } from '../fanLocal.data';
+const props = defineProps({
+    devicekide: {
+        type: String,
+        default: '',
+    },
+    historyList: {
+        type: Array,
+        default: () => {
+            return []
+        }
+    },
+    chartsColumns: {
+        type: Array,
+        default: () => {
+            return []
+        }
+    }
+});
+let scroll = reactive({
+    y: 700,
+});
+let historyLists = ref<any[]>([])
+let chartsColumn = ref<any[]>([])
+
+watch(() => props.historyList, (newH, oldH) => {
+    historyLists.value = newH
+},
+    { immediate: true })
+watch(() => props.chartsColumns, (newC, oldC) => {
+    chartsColumn.value = newC
+}, {
+    immediate: true
+})
+
+
+</script>
+<style lang="less" scoped>
+.alarm-history {
+    width: 100%;
+    height: 730px;
+    position: fixed;
+    top: 100px;
+}
+</style>

+ 59 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-history.vue

@@ -0,0 +1,59 @@
+<template>
+    <div class="alarm-history">
+        <template v-if="globalConfig.History_Type == 'remote'">
+                <HistoryTable
+                  :columns-type="`${selectDatas.deviceType}`"
+                  :device-type="`${devicekide}`"
+                  designScope="fanlocal-history"
+                  :scroll="scroll"
+                />
+              </template>
+              <template v-else>
+                <HistoryTable1 class="w-100% h-100%" :device-code="`${devicekide}`" :scroll="scroll" dict-code="fanlocal_dict" />
+              </template>
+    </div>
+</template>
+<script setup lang="ts">
+import { onBeforeMount, ref, watch, onMounted, nextTick, defineAsyncComponent, reactive, onUnmounted, inject, unref } from 'vue';
+import HistoryTable from '../../comment/HistoryTable.vue'
+import HistoryTable1 from '../../../../vent/comment/history/HistoryTable.vue'
+
+const props = defineProps({
+    selectData: {
+        type: Object,
+        default: () => {
+            return {}
+        }
+    },
+    devicekide:{
+        type:String,
+        default:'',
+    },
+    globalConfig:{
+        type:Object,
+        default:()=>{
+            return {}
+        },
+    }
+});
+
+let selectDatas = reactive({})
+let scroll = reactive({
+  y: 700,
+});
+
+watch(() => props.selectData, (newS, oldS) => {
+    selectDatas = Object.assign({}, newS)
+}, {
+    immediate: true,
+    deep: true
+})
+</script>
+<style lang="less" scoped>
+.alarm-history {
+    width: 100%;
+    height: 730px;
+    position: fixed;
+    top: 100px;
+}
+</style>

+ 36 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-operate-history.vue

@@ -0,0 +1,36 @@
+<template>
+    <div class="alarm-history">
+        <HandlerHistoryTable
+                columns-type="operator_history"
+                :device-type="`${devicekide}`"
+                :device-list-api="baseList"
+                designScope="alarm-history"
+                :scroll="scroll"
+              />
+    </div>
+</template>
+<script setup lang="ts">
+import { onBeforeMount, ref, watch, onMounted, nextTick, defineAsyncComponent, reactive, onUnmounted, inject, unref } from 'vue';
+import HandlerHistoryTable from '../../comment/HandlerHistoryTable.vue';
+import { list as baseList } from '../../../deviceManager/fanTabel/fan.api';
+
+const props = defineProps({
+    devicekide:{
+        type:String,
+        default:'',
+    },
+});
+let scroll = reactive({
+  y: 700,
+});
+
+
+</script>
+<style lang="less" scoped>
+.alarm-history {
+    width: 100%;
+    height: 730px;
+    position: fixed;
+    top: 100px;
+}
+</style>

+ 29 - 0
src/views/vent/monitorManager/fanLocalMonitor1/components/fanlocal-warn-history.vue

@@ -0,0 +1,29 @@
+<template>
+    <div class="alarm-history">
+        <AlarmHistoryTable columns-type="alarm" :device-type="`${devicekide}`" designScope="alarm-history" :scroll="scroll" />
+    </div>
+</template>
+<script setup lang="ts">
+import { onBeforeMount, ref, watch, onMounted, nextTick, defineAsyncComponent, reactive, onUnmounted, inject, unref } from 'vue';
+import AlarmHistoryTable from '../../comment/AlarmHistoryTable.vue';
+
+const props = defineProps({
+    devicekide:{
+        type:String,
+        default:'',
+    },
+});
+let scroll = reactive({
+  y: 700,
+});
+
+
+</script>
+<style lang="less" scoped>
+.alarm-history {
+    width: 100%;
+    height: 730px;
+    position: fixed;
+    top: 100px;
+}
+</style>

+ 65 - 0
src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.api.ts

@@ -0,0 +1,65 @@
+import { defHttp } from '/@/utils/http/axios';
+import { Modal } from 'ant-design-vue';
+
+enum Api {
+  list = '/monitor/device',
+  save = '/safety/ventanalyGate/add',
+  edit = '/safety/ventanalyGate/edit',
+  baseList = '/safety/ventanalyWindow/list',
+  deleteById = '/safety/ventanalyGate/delete',
+  deleteBatch = '/sys/user/deleteBatch',
+  importExcel = '/sys/user/importExcel',
+  exportXls = '/sys/user/exportXls',
+  autoAdjust = '/safety/ventanalyFan/updateFanlocalAutoAdjustStatus',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });
+
+export const getTableList = (params) => defHttp.get({ url: Api.baseList, params });
+export const autoAdjust = (params) => defHttp.post({ url: Api.autoAdjust, params });
+
+/**
+ * 删除用户
+ */
+export const deleteById = (params, handleSuccess) => {
+  return defHttp.delete({ url: Api.deleteById, params }, { joinParamsToUrl: true }).then(() => {
+    handleSuccess();
+  });
+};
+/**
+ * 批量删除用户
+ * @param params
+ */
+export const batchDeleteById = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+        handleSuccess();
+      });
+    },
+  });
+};
+/**
+ * 保存或者更新用户
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  const url = isUpdate ? Api.edit : Api.save;
+  return defHttp.put({ url: url, params });
+};

+ 3961 - 0
src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.data.ts

@@ -0,0 +1,3961 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { rules } from '/@/utils/helper/validator';
+import { ref, reactive } from 'vue';
+import { cloneDeep } from 'lodash-es';
+export const navList = ref([
+  {
+    title: '实时监控',
+    pathName: 'fanLocal-ssjc',
+    isHover: false,
+  },
+  {
+    title: '历史监测记录',
+    pathName: 'fanLocal-history',
+    isHover: false,
+  },
+  {
+    title: '报警历史记录',
+    pathName: 'fanLocal-warn',
+    isHover: false,
+  },
+  {
+    title: '操作历史记录',
+    pathName: 'fanLocal-operate',
+    isHover: false,
+  },
+  {
+    title: '风量实时曲线',
+    pathName: 'fanLocal-wind',
+    isHover: false,
+  },
+]);
+export const columns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 120,
+  },
+  {
+    title: '安装位置',
+    dataIndex: 'strinstallpos',
+    width: 100,
+  },
+  {
+    title: '是否为常闭型',
+    dataIndex: 'bnormalclose',
+    width: 100,
+    // customRender: render.renderAvatar,
+  },
+  {
+    title: '净宽',
+    dataIndex: 'fclearwidth',
+    width: 80,
+  },
+  {
+    title: '净高',
+    dataIndex: 'fclearheight',
+    width: 100,
+  },
+  {
+    title: '风门道数',
+    dataIndex: 'ndoorcount',
+    width: 100,
+  },
+  {
+    title: '所属分站',
+    width: 150,
+    dataIndex: 'stationname',
+  },
+  {
+    title: '点表',
+    width: 100,
+    dataIndex: 'strtype',
+  },
+  {
+    title: '监测类型',
+    dataIndex: 'monitorflag',
+    width: 100,
+  },
+  {
+    title: '是否模拟数据',
+    dataIndex: 'testflag',
+    width: 100,
+  },
+];
+
+export const recycleColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+  },
+  {
+    title: '是否为常闭型',
+    dataIndex: 'bnormalclose',
+    width: 100,
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '名称',
+    field: 'strname',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '安装位置',
+    field: 'strinstallpos',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '是否为常闭型',
+    field: 'bnormalclose',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择读写类型',
+      stringToNumber: true,
+    },
+    colProps: { span: 6 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '名称',
+    field: 'strname',
+    component: 'Input',
+  },
+  {
+    label: '安装位置',
+    field: 'strinstallpos',
+    component: 'Input',
+  },
+  {
+    label: '是否为常闭型',
+    field: 'bnormalclose',
+    component: 'RadioGroup',
+    defaultValue: 1,
+    componentProps: () => {
+      return {
+        options: [
+          { label: '是', value: 1, key: '1' },
+          { label: '否', value: 0, key: '2' },
+        ],
+      };
+    },
+  },
+  {
+    label: '净宽',
+    field: 'fclearwidth',
+    component: 'Input',
+  },
+  {
+    label: '净高',
+    field: 'fclearheight',
+    component: 'Input',
+  },
+  {
+    label: '风门道数',
+    field: 'ndoorcount',
+    component: 'Input',
+  },
+  {
+    label: '所属分站',
+    field: 'stationname',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择状态',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '点表',
+    field: 'strtype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择状态',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '监测类型',
+    field: 'monitorflag',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择状态',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '是否模拟数据',
+    field: 'testflag',
+    component: 'RadioGroup',
+    defaultValue: 1,
+    componentProps: () => {
+      return {
+        options: [
+          { label: '是', value: 1, key: '1' },
+          { label: '否', value: 0, key: '2' },
+        ],
+      };
+    },
+  },
+];
+
+export const formPasswordSchema: FormSchema[] = [
+  {
+    label: '用户账号',
+    field: 'username',
+    component: 'Input',
+    componentProps: { readOnly: true },
+  },
+  {
+    label: '登录密码',
+    field: 'password',
+    component: 'StrengthMeter',
+    componentProps: {
+      placeholder: '请输入登录密码',
+    },
+    rules: [
+      {
+        required: true,
+        message: '请输入登录密码',
+      },
+    ],
+  },
+  {
+    label: '确认密码',
+    field: 'confirmPassword',
+    component: 'InputPassword',
+    dynamicRules: ({ values }) => rules.confirmPassword(values, true),
+  },
+];
+
+export const formAgentSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'userName',
+    label: '用户名',
+    component: 'Input',
+    componentProps: {
+      readOnly: true,
+      allowClear: false,
+    },
+  },
+  {
+    field: 'agentUserName',
+    label: '代理人用户名',
+    required: true,
+    component: 'JSelectUser',
+    componentProps: {
+      rowKey: 'username',
+      labelKey: 'realname',
+      maxSelectCount: 10,
+    },
+  },
+  {
+    field: 'startTime',
+    label: '代理开始时间',
+    component: 'DatePicker',
+    required: true,
+    componentProps: {
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      placeholder: '请选择代理开始时间',
+    },
+  },
+  {
+    field: 'endTime',
+    label: '代理结束时间',
+    component: 'DatePicker',
+    required: true,
+    componentProps: {
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      placeholder: '请选择代理结束时间',
+    },
+  },
+  {
+    field: 'status',
+    label: '状态',
+    component: 'JDictSelectTag',
+    defaultValue: '1',
+    componentProps: {
+      dictCode: 'valid_status',
+      type: 'radioButton',
+    },
+  },
+];
+
+export const chartsColumns = [
+  {
+    legend: '瓦斯浓度',
+    seriesName: '瓦斯浓度(%)',
+    ymax: 100,
+    yname: '%',
+    linetype: 'bar',
+    yaxispos: 'left',
+    color: '#cd5fff',
+    sort: 1,
+    dataIndex: '',
+    xRotate: 0,
+  },
+];
+export const chartsColumns1 = [
+  {
+    legend: '风量',
+    seriesName: 'm³/min',
+    ymax: 1000,
+    yname: '',
+    linetype: 'line',
+    yaxispos: 'left',
+    color: '#755cf8',
+    sort: 1,
+    dataIndex: 'windQuantity2',
+    xRotate: 0,
+  },
+];
+
+export const transformMobileH = [
+  {
+    title: 'A相电流(A)',
+    code: '',
+  },
+  {
+    title: 'B相电流(A)',
+    code: '',
+  },
+  {
+    title: 'C相电流(A)',
+    code: '',
+  },
+  {
+    title: '电压(V)',
+    code: '',
+  },
+  {
+    title: '温度(℃)',
+    code: '',
+  },
+  {
+    title: '额定电流(A)',
+    code: '',
+  },
+  {
+    title: '短路电流(A)',
+    code: '',
+  },
+];
+
+export const transformMobileL = [
+  {
+    title: 'A相电流(A)',
+    code: '',
+  },
+  {
+    title: 'B相电流(A)',
+    code: '',
+  },
+  {
+    title: 'C相电流(A)',
+    code: '',
+  },
+  {
+    title: '电压(V)',
+    code: '',
+  },
+  {
+    title: '功率(KW)',
+    code: '',
+  },
+  {
+    title: '额定电流(A)',
+    code: '',
+  },
+  {
+    title: '短路电流(A)',
+    code: '',
+  },
+];
+
+export const protectionEnableH = [
+  {
+    title: '短路',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '不平衡',
+    code: '',
+    value: '未使能',
+  },
+  {
+    title: '过载',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '过压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '欠压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '短路延时(ms)',
+    code: '',
+    value: 0,
+  },
+  {
+    title: '过压延时(s)',
+    code: '',
+    value: 10,
+  },
+  {
+    title: '欠压延时(s)',
+    code: '',
+    value: 10,
+  },
+];
+
+export const protectionEnableL = [
+  {
+    title: '短路',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '不平衡',
+    code: '',
+    value: '未使能',
+  },
+  {
+    title: '过载',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '过压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '欠压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '漏电',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '漏电闭锁',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '漏电延时(ms)',
+    code: '',
+    value: 10,
+  },
+  {
+    title: '短路延时(ms)',
+    code: '',
+    value: 1,
+  },
+  {
+    title: '过压延时(s)',
+    code: '',
+    value: 10,
+  },
+  {
+    title: '欠压延时(s)',
+    code: '',
+    value: 10,
+  },
+];
+
+export const electricMonitor = {
+  电流: [
+    {
+      title: 'A相电流 (A)',
+      code: '',
+    },
+    {
+      title: 'B相电流 (A)',
+      code: '',
+    },
+    {
+      title: 'C相电流 (A)',
+      code: '',
+    },
+    {
+      title: '额定电流 (A)',
+      code: '',
+    },
+  ],
+  电压: [
+    {
+      title: 'Uac (V)',
+      code: '',
+    },
+    {
+      title: '功率 (KW)',
+      code: '',
+    },
+  ],
+  保护状态: [
+    {
+      title: '短路',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '失压',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '过载',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '过压',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '缺相',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '漏电保护',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '相不平衡',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '漏电闭锁',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '瓦斯闭锁',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '选择性漏电保护',
+      code: '',
+      value: 1,
+    },
+  ],
+};
+
+export const electricState = [
+  {
+    title: '额定电流(A)',
+    code: '',
+    value: 100.0,
+  },
+  {
+    title: '额定电压(V)',
+    code: '',
+    value: 660,
+  },
+  {
+    title: '短路倍数',
+    code: '',
+    value: 8,
+  },
+  {
+    title: '欠压倍数',
+    code: '',
+    value: 0.85,
+  },
+  {
+    title: '漏电延时(s)',
+    code: '',
+    value: 5.0,
+  },
+  {
+    title: '不平衡倍数',
+    code: '',
+    value: 0.0,
+  },
+  {
+    title: '漏电闭锁(KΩ)',
+    code: '',
+    value: 11,
+  },
+  {
+    title: '末端短路倍数',
+    code: '',
+    value: 1.0,
+  },
+  {
+    title: '相敏倍数',
+    code: '',
+    value: 41.0,
+  },
+  {
+    title: '过压延时(s)',
+    code: '',
+    value: 1.2,
+  },
+  {
+    title: '过压定值',
+    code: '',
+    value: 1.2,
+  },
+];
+
+export const fanControlState1 = {
+  电流电压: {
+    'la1(A)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+    'lb1(A)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+    'lc1(A)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+    '额定电流(A)': [
+      {
+        code: '',
+        value: 55.0,
+      },
+      {
+        code: '',
+        value: 55.0,
+      },
+    ],
+    'Uac(V)': [
+      {
+        code: '',
+        value: 658,
+      },
+    ],
+  },
+  功率: {
+    '功率(KW)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+  },
+  运行状态: {
+    开合闸状态: [
+      {
+        code: '',
+        value: 0,
+      },
+      {
+        code: '',
+        value: 0,
+      },
+    ],
+  },
+};
+export const fanControlState2 = {
+  电流电压: {
+    'la1(A)': [
+      {
+        code: '',
+        value: 35.0,
+      },
+      {
+        code: '',
+        value: 28.0,
+      },
+    ],
+    'lb1(A)': [
+      {
+        code: '',
+        value: 34.0,
+      },
+      {
+        code: '',
+        value: 28.0,
+      },
+    ],
+    'lc1(A)': [
+      {
+        code: '',
+        value: 34.0,
+      },
+      {
+        code: '',
+        value: 29.0,
+      },
+    ],
+    '额定电流(A)': [
+      {
+        code: '',
+        value: 75.0,
+      },
+      {
+        code: '',
+        value: 75.0,
+      },
+    ],
+    'Uac(V)': [
+      {
+        code: '',
+        value: 697,
+      },
+    ],
+  },
+  功率: {
+    '功率(KW)': [
+      {
+        code: '',
+        value: 42,
+      },
+      {
+        code: '',
+        value: 34,
+      },
+    ],
+  },
+  运行状态: {
+    开合闸状态: [
+      {
+        code: '',
+        value: 1,
+      },
+      {
+        code: '',
+        value: 1,
+      },
+    ],
+  },
+};
+
+export const fanSetting1 = [
+  {
+    title: 'I额定电流(A)',
+    code: '',
+    value: '55',
+  },
+  {
+    title: 'II额定电流(A)',
+    code: '',
+    value: '55',
+  },
+  {
+    title: '电压等级(V)',
+    code: '',
+    value: '660',
+  },
+  {
+    title: 'I速断定值',
+    code: '',
+    value: '8',
+  },
+  {
+    title: 'II速断定值',
+    code: '',
+    value: '8',
+  },
+  {
+    title: '欠压定值',
+    code: '',
+    value: '1',
+  },
+  {
+    title: '欠压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: '过压定值',
+    code: '',
+    value: '1',
+  },
+  {
+    title: '过压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: 'I启动II延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '启动对侧延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '风电瓦斯延时(s)',
+    code: '',
+    value: '0',
+  },
+];
+
+export const fanSetting2 = [
+  {
+    title: 'I额定电流(A)',
+    code: '',
+    value: '75',
+  },
+  {
+    title: 'II额定电流(A)',
+    code: '',
+    value: '75',
+  },
+  {
+    title: '电压等级(V)',
+    code: '',
+    value: '660',
+  },
+  {
+    title: 'I速断定值',
+    code: '',
+    value: '8',
+  },
+  {
+    title: 'II速断定值',
+    code: '',
+    value: '9',
+  },
+  {
+    title: '欠压定值',
+    code: '',
+    value: '0',
+  },
+  {
+    title: '欠压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: '过压定值',
+    code: '',
+    value: '1',
+  },
+  {
+    title: '过压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: 'I启动II延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '启动对侧延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '风电瓦斯延时(s)',
+    code: '',
+    value: '0',
+  },
+];
+
+export const data_model = ref<any>({
+  layout_center: { x: 727, y: 226 },
+  config: {
+    background_color: '#00000000',
+    scale: 0.9,
+    position_center: { x: 0, y: 0 },
+    svg_position_center: { x: 50, y: 50 },
+    grid: true,
+    ruler: false,
+  },
+  done_json: [
+    {
+      id: 'connection_lineSAVIxZbu1U',
+      x: -322,
+      y: 297,
+      client: { x: -345, y: 316 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -345.5, y: 292 },
+        tc: { x: -345, y: 292 },
+        tr: { x: -344.5, y: 292 },
+        l: { x: -345.5, y: 316 },
+        r: { x: -344.5, y: 316 },
+        bl: { x: -345.5, y: 340 },
+        bc: { x: -345, y: 340 },
+        br: { x: -344.5, y: 340 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 47 },
+            { x: 50, y: 20 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_lineYOym7m1COw',
+      x: -499,
+      y: 293,
+      client: { x: -499, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -499.5, y: 289 },
+        tc: { x: -499, y: 289 },
+        tr: { x: -498.5, y: 289 },
+        l: { x: -499.5, y: 313 },
+        r: { x: -498.5, y: 313 },
+        bl: { x: -499.5, y: 337 },
+        bc: { x: -499, y: 337 },
+        br: { x: -498.5, y: 337 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 51, y: 53 },
+            { x: 51, y: 21 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'arrowWVIq74qgBO',
+      x: -520.5,
+      y: -143,
+      client: { x: -520.5, y: -143 },
+      scale_x: 0.45,
+      scale_y: 0.44799998632812543,
+      rotate: 179.9812559818536,
+      actual_bound: { x: 0.0000014901161193847656, y: 14.285714149475098, width: 100, height: 71.42857360839844 },
+      point_coordinate: {
+        tl: { x: -497.9947668868031, y: -127.00736161477208 },
+        tc: { x: -520.494765682786, y: -127.00000085618991 },
+        tr: { x: -542.994764478769, y: -126.99264009760776 },
+        l: { x: -498.00000120401705, y: -143.00736075858217 },
+        r: { x: -542.999998795983, y: -142.99263924141783 },
+        bl: { x: -498.00523552123104, y: -159.00735990239224 },
+        bc: { x: -520.505234317214, y: -158.99999914381007 },
+        br: { x: -543.0052331131969, y: -158.99263838522793 },
+      },
+      name: 'arrow',
+      title: '箭头',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrowUFvMb6HR6G',
+      x: -298.5,
+      y: -142,
+      client: { x: -302.5, y: -142 },
+      scale_x: 0.45,
+      scale_y: 0.44799998632812543,
+      rotate: 0,
+      actual_bound: { x: 0.0000014901161193847656, y: 14.285714149475098, width: 100, height: 71.42857360839844 },
+      point_coordinate: {
+        tl: { x: -325, y: -158 },
+        tc: { x: -302.5, y: -158 },
+        tr: { x: -280, y: -158 },
+        l: { x: -325, y: -142 },
+        r: { x: -280, y: -142 },
+        bl: { x: -325, y: -126 },
+        bc: { x: -302.5, y: -126 },
+        br: { x: -280, y: -126 },
+      },
+      name: 'arrow',
+      title: '箭头-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineTy3uyr5DOv',
+      x: 508,
+      y: 177,
+      client: { x: 508, y: 177 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -551.999998795983, y: -137.99263924141783 },
+        tc: { x: -551.999998795983, y: -137.99263924141783 },
+        tr: { x: -551.999998795983, y: -137.99263924141783 },
+        l: { x: -551.999998795983, y: -137.99263924141783 },
+        r: { x: -551.999998795983, y: -137.99263924141783 },
+        bl: { x: -551.999998795983, y: -137.99263924141783 },
+        bc: { x: -551.999998795983, y: -137.99263924141783 },
+        br: { x: -551.999998795983, y: -137.99263924141783 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: { title: '点坐标', type: 'JsonEdit', val: [{ x: 50, y: 50 }] },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'Right', target_id: 'arrowWVIq74qgBO' }, end: null },
+    },
+    {
+      id: 'rect3OD1llFsFbQ',
+      x: -688,
+      y: -224.5,
+      client: { x: -688, y: -224.5 },
+      scale_x: 1.9694118000598109,
+      scale_y: 0.3599999890136722,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -781, y: -227 },
+        tc: { x: -688, y: -227 },
+        tr: { x: -595, y: -227 },
+        l: { x: -781, y: -224.5 },
+        r: { x: -595, y: -224.5 },
+        bl: { x: -781, y: -222 },
+        bc: { x: -688, y: -222 },
+        br: { x: -595, y: -222 },
+      },
+      name: 'rect3',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect3z6ep3DMpbX',
+      x: -138,
+      y: -226.5,
+      client: { x: -138, y: -226.5 },
+      scale_x: 1.9694118000598109,
+      scale_y: 0.3599999890136722,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -231, y: -229 },
+        tc: { x: -138, y: -229 },
+        tr: { x: -45, y: -229 },
+        l: { x: -231, y: -226.5 },
+        r: { x: -45, y: -226.5 },
+        bl: { x: -231, y: -224 },
+        bc: { x: -138, y: -224 },
+        br: { x: -45, y: -224 },
+      },
+      name: 'rect3',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineYTEQVhroc2',
+      x: -542.999998795983,
+      y: -142.99263924141783,
+      client: { x: 588, y: 224 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -585.999998795983, y: -185.99263924141783 },
+        tc: { x: -542.999998795983, y: -185.99263924141783 },
+        tr: { x: -499.99999879598295, y: -185.99263924141783 },
+        l: { x: -585.999998795983, y: -142.99263924141783 },
+        r: { x: -499.99999879598295, y: -142.99263924141783 },
+        bl: { x: -585.999998795983, y: -99.99263924141783 },
+        bc: { x: -542.999998795983, y: -99.99263924141783 },
+        br: { x: -499.99999879598295, y: -99.99263924141783 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: -36, y: 51 },
+            { x: -36, y: -35 },
+            { x: -34, y: -34 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'Right', target_id: 'arrowWVIq74qgBO' }, end: null },
+    },
+    {
+      id: 'connection_lineHE0iHAc7sh',
+      x: -107.99999879598295,
+      y: -139.99263924141783,
+      client: { x: -107.99999879598295, y: -139.99263924141783 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -150.99999879598295, y: -182.99263924141783 },
+        tc: { x: -107.99999879598295, y: -182.99263924141783 },
+        tr: { x: -64.99999879598295, y: -182.99263924141783 },
+        l: { x: -150.99999879598295, y: -139.99263924141783 },
+        r: { x: -64.99999879598295, y: -139.99263924141783 },
+        bl: { x: -150.99999879598295, y: -96.99263924141783 },
+        bc: { x: -107.99999879598295, y: -96.99263924141783 },
+        br: { x: -64.99999879598295, y: -96.99263924141783 },
+      },
+      name: 'connection_line',
+      title: '连接线-copy',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: -124, y: 49 },
+            { x: -35, y: 49 },
+            { x: -36, y: -35 },
+            { x: -34, y: -34 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'Right', target_id: 'arrowWVIq74qgBO' }, end: null },
+    },
+    {
+      id: 'straight-lineGewWfZACIy',
+      x: -688,
+      y: -222,
+      client: { x: 452, y: 146 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -688.5, y: -284 },
+        tc: { x: -688, y: -284 },
+        tr: { x: -687.5, y: -284 },
+        l: { x: -688.5, y: -222 },
+        r: { x: -687.5, y: -222 },
+        bl: { x: -688.5, y: -160 },
+        bc: { x: -688, y: -160 },
+        br: { x: -687.5, y: -160 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 49, y: 174 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect3OD1llFsFbQ' }, end: null },
+    },
+    {
+      id: 'connection_linekOe9aqybJ7',
+      x: -132,
+      y: -227,
+      client: { x: -132, y: -227 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -132.5, y: -289 },
+        tc: { x: -132, y: -289 },
+        tr: { x: -131.5, y: -289 },
+        l: { x: -132.5, y: -227 },
+        r: { x: -131.5, y: -227 },
+        bl: { x: -132.5, y: -165 },
+        bc: { x: -132, y: -165 },
+        br: { x: -131.5, y: -165 },
+      },
+      name: 'connection_line',
+      title: '连接线-copy',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 50, y: 180 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect3OD1llFsFbQ' }, end: null },
+    },
+    {
+      id: 'rect1u3AJvpzHYv',
+      x: -689.5,
+      y: -63,
+      client: { x: -689.5, y: -63 },
+      scale_x: 0.7082353259023925,
+      scale_y: 0.7259259095159254,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -711, y: -98 },
+        tc: { x: -689.5, y: -98 },
+        tr: { x: -668, y: -98 },
+        l: { x: -711, y: -63 },
+        r: { x: -668, y: -63 },
+        bl: { x: -711, y: -28 },
+        bc: { x: -689.5, y: -28 },
+        br: { x: -668, y: -28 },
+      },
+      name: 'rect1',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#ff0000', closeVal: '#ff0000' }, fill: { openVal: '#ff0000', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect1sMuXufr2Gk',
+      x: -133.5,
+      y: -63,
+      client: { x: -133.5, y: -69 },
+      scale_x: 0.7082353259023925,
+      scale_y: 0.7259259095159254,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -155, y: -104 },
+        tc: { x: -133.5, y: -104 },
+        tr: { x: -112, y: -104 },
+        l: { x: -155, y: -69 },
+        r: { x: -112, y: -69 },
+        bl: { x: -155, y: -34 },
+        bc: { x: -133.5, y: -34 },
+        br: { x: -112, y: -34 },
+      },
+      name: 'rect1',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#ff0000', closeVal: '#ff0000' }, fill: { openVal: '#ff0000', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-linevfbRmEjOka',
+      x: -689.5,
+      y: -28,
+      client: { x: 452, y: 336 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -690, y: -57.5 },
+        tc: { x: -689.5, y: -57.5 },
+        tr: { x: -689, y: -57.5 },
+        l: { x: -690, y: -28 },
+        r: { x: -689, y: -28 },
+        bl: { x: -690, y: 1.5 },
+        bc: { x: -689.5, y: 1.5 },
+        br: { x: -689, y: 1.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 49, y: 109 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect1u3AJvpzHYv' }, end: null },
+    },
+    {
+      id: 'connection_line8SKNmdI7NY',
+      x: -133.5,
+      y: -27,
+      client: { x: -133.5, y: -27 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -134, y: -56.5 },
+        tc: { x: -133.5, y: -56.5 },
+        tr: { x: -133, y: -56.5 },
+        l: { x: -134, y: -27 },
+        r: { x: -133, y: -27 },
+        bl: { x: -134, y: 2.5 },
+        bc: { x: -133.5, y: 2.5 },
+        br: { x: -133, y: 2.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 49, y: 109 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect1u3AJvpzHYv' }, end: null },
+    },
+    {
+      id: 'electric-transformerRBBJGgk12b',
+      x: -687,
+      y: 81,
+      client: { x: -687, y: 81 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 1, y: 1, width: 88, height: 160 },
+      point_coordinate: {
+        tl: { x: -731, y: 1 },
+        tc: { x: -687, y: 1 },
+        tr: { x: -643, y: 1 },
+        l: { x: -731, y: 81 },
+        r: { x: -643, y: 81 },
+        bl: { x: -731, y: 161 },
+        bc: { x: -687, y: 161 },
+        br: { x: -643, y: 161 },
+      },
+      name: 'electric-transformer',
+      title: '变压器',
+      tag: 'electric-transformer',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { isOpen: { title: '开关', type: 'Switch', val: false } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'electric-transformerWFdpgdmG1o',
+      x: -129,
+      y: 80,
+      client: { x: -129, y: 80 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 1, y: 1, width: 88, height: 160 },
+      point_coordinate: {
+        tl: { x: -173, y: 0 },
+        tc: { x: -129, y: 0 },
+        tr: { x: -85, y: 0 },
+        l: { x: -173, y: 80 },
+        r: { x: -85, y: 80 },
+        bl: { x: -173, y: 160 },
+        bc: { x: -129, y: 160 },
+        br: { x: -85, y: 160 },
+      },
+      name: 'electric-transformer',
+      title: '变压器-copy',
+      tag: 'electric-transformer',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { isOpen: { title: '开关', type: 'Switch', val: false } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineQunQ4hosc2',
+      x: -692,
+      y: 193,
+      client: { x: -692, y: 193 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -692, y: 114.5 },
+        tc: { x: -692, y: 114.5 },
+        tr: { x: -692, y: 114.5 },
+        l: { x: -692, y: 193 },
+        r: { x: -692, y: 193 },
+        bl: { x: -692, y: 271.5 },
+        bc: { x: -692, y: 271.5 },
+        br: { x: -692, y: 271.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 50, y: 207 },
+            { x: 50, y: 207 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'electric-transformerRBBJGgk12b' }, end: null },
+    },
+    {
+      id: 'connection_lineVp68SNcEFL',
+      x: -132,
+      y: 192,
+      client: { x: -134, y: 193 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -134, y: 114.5 },
+        tc: { x: -134, y: 114.5 },
+        tr: { x: -134, y: 114.5 },
+        l: { x: -134, y: 193 },
+        r: { x: -134, y: 193 },
+        bl: { x: -134, y: 271.5 },
+        bc: { x: -134, y: 271.5 },
+        br: { x: -134, y: 271.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 50, y: 207 },
+            { x: 50, y: 207 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'electric-transformerRBBJGgk12b' }, end: null },
+    },
+    {
+      id: 'rect2b2ua906HAT',
+      x: -695,
+      y: 266.5,
+      client: { x: -695, y: 266.5 },
+      scale_x: 0.677647070988322,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -727, y: 263 },
+        tc: { x: -695, y: 263 },
+        tr: { x: -663, y: 263 },
+        l: { x: -727, y: 266.5 },
+        r: { x: -663, y: 266.5 },
+        bl: { x: -727, y: 270 },
+        bc: { x: -695, y: 270 },
+        br: { x: -663, y: 270 },
+      },
+      name: 'rect2',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect2iNmTsLMCnq',
+      x: -132,
+      y: 268.5,
+      client: { x: -132, y: 268.5 },
+      scale_x: 0.677647070988322,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -164, y: 265 },
+        tc: { x: -132, y: 265 },
+        tr: { x: -100, y: 265 },
+        l: { x: -164, y: 268.5 },
+        r: { x: -100, y: 268.5 },
+        bl: { x: -164, y: 272 },
+        bc: { x: -132, y: 272 },
+        br: { x: -100, y: 272 },
+      },
+      name: 'rect2',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rectiQQbMJHYM9',
+      x: -692.5,
+      y: 388.5,
+      client: { x: -692.5, y: 388.5 },
+      scale_x: 0.7411765038513409,
+      scale_y: 0.7777777601956344,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -715, y: 351 },
+        tc: { x: -692.5, y: 351 },
+        tr: { x: -670, y: 351 },
+        l: { x: -715, y: 388.5 },
+        r: { x: -670, y: 388.5 },
+        bl: { x: -715, y: 426 },
+        bc: { x: -692.5, y: 426 },
+        br: { x: -670, y: 426 },
+      },
+      name: 'rect',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rectjl8XE7uvYW',
+      x: -132.5,
+      y: 387.5,
+      client: { x: -132.5, y: 382.5 },
+      scale_x: 0.7411765038513409,
+      scale_y: 0.7777777601956344,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -155, y: 345 },
+        tc: { x: -132.5, y: 345 },
+        tr: { x: -110, y: 345 },
+        l: { x: -155, y: 382.5 },
+        r: { x: -110, y: 382.5 },
+        bl: { x: -155, y: 420 },
+        bc: { x: -132.5, y: 420 },
+        br: { x: -110, y: 420 },
+      },
+      name: 'rect',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-linetgtW9T3tlM',
+      x: -693,
+      y: 477,
+      client: { x: -693, y: 477 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -702.1135158538818, y: 429.05868911743164 },
+        tc: { x: -693, y: 429.05868911743164 },
+        tr: { x: -683.8864841461182, y: 429.05868911743164 },
+        l: { x: -702.1135158538818, y: 477 },
+        r: { x: -683.8864841461182, y: 477 },
+        bl: { x: -702.1135158538818, y: 524.9413108825684 },
+        bc: { x: -693, y: 524.9413108825684 },
+        br: { x: -683.8864841461182, y: 524.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-lineB8uDtRCKgx',
+      x: -133,
+      y: 477,
+      client: { x: -134, y: 476 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -143.11351585388184, y: 428.05868911743164 },
+        tc: { x: -134, y: 428.05868911743164 },
+        tr: { x: -124.88648414611816, y: 428.05868911743164 },
+        l: { x: -143.11351585388184, y: 476 },
+        r: { x: -124.88648414611816, y: 476 },
+        bl: { x: -143.11351585388184, y: 523.9413108825684 },
+        bc: { x: -134, y: 523.9413108825684 },
+        br: { x: -124.88648414611816, y: 523.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-linewAYhKBlISA',
+      x: -693,
+      y: 524.9413108825684,
+      client: { x: 450, y: 889 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -742, y: 393.94131088256836 },
+        tc: { x: -693, y: 393.94131088256836 },
+        tr: { x: -644, y: 393.94131088256836 },
+        l: { x: -742, y: 524.9413108825684 },
+        r: { x: -644, y: 524.9413108825684 },
+        bl: { x: -742, y: 655.9413108825684 },
+        bc: { x: -693, y: 655.9413108825684 },
+        br: { x: -644, y: 655.9413108825684 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 134, y: 50 },
+            { x: 135, y: -205 },
+            { x: 140, y: -209 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'arrow-linetgtW9T3tlM' }, end: null },
+    },
+    {
+      id: 'connection_linezKEzYcoJeW',
+      x: -335,
+      y: 524.9413108825684,
+      client: { x: -335, y: 524.9413108825684 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -388, y: 393.94131088256836 },
+        tc: { x: -335, y: 393.94131088256836 },
+        tr: { x: -282, y: 393.94131088256836 },
+        l: { x: -388, y: 524.9413108825684 },
+        r: { x: -282, y: 524.9413108825684 },
+        bl: { x: -388, y: 655.9413108825684 },
+        bc: { x: -335, y: 655.9413108825684 },
+        br: { x: -282, y: 655.9413108825684 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 253, y: 50 },
+            { x: 172, y: 51 },
+            { x: 173, y: -208 },
+            { x: 173, y: -208 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'arrow-linetgtW9T3tlM' }, end: null },
+    },
+    {
+      id: 'rect20w5PJBsB2x',
+      x: -539.5,
+      y: 268.5,
+      client: { x: -539.5, y: 268.5 },
+      scale_x: 1.810588267796923,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -625, y: 265 },
+        tc: { x: -539.5, y: 265 },
+        tr: { x: -454, y: 265 },
+        l: { x: -625, y: 268.5 },
+        r: { x: -454, y: 268.5 },
+        bl: { x: -625, y: 272 },
+        bc: { x: -539.5, y: 272 },
+        br: { x: -454, y: 272 },
+      },
+      name: 'rect2',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect2RxYeI9K6JU',
+      x: -272.5,
+      y: 267.5,
+      client: { x: -272.5, y: 267.5 },
+      scale_x: 1.810588267796923,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -358, y: 264 },
+        tc: { x: -272.5, y: 264 },
+        tr: { x: -187, y: 264 },
+        l: { x: -358, y: 267.5 },
+        r: { x: -187, y: 267.5 },
+        bl: { x: -358, y: 271 },
+        bc: { x: -272.5, y: 271 },
+        br: { x: -187, y: 271 },
+      },
+      name: 'rect2',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text662jqUKDwd',
+      x: -102,
+      y: -64,
+      client: { x: -102, y: -64 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -117.5, y: -74 },
+        tc: { x: -102, y: -74 },
+        tr: { x: -86.5, y: -74 },
+        l: { x: -117.5, y: -64 },
+        r: { x: -86.5, y: -64 },
+        bl: { x: -117.5, y: -54 },
+        bc: { x: -102, y: -54 },
+        br: { x: -86.5, y: -54 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '主风机移变' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineqQLg7eRl0i',
+      x: -502,
+      y: 295,
+      client: { x: -485, y: 314 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -512, y: 314 },
+        tc: { x: -485, y: 314 },
+        tr: { x: -458, y: 314 },
+        l: { x: -512, y: 314 },
+        r: { x: -458, y: 314 },
+        bl: { x: -512, y: 314 },
+        bc: { x: -485, y: 314 },
+        br: { x: -458, y: 314 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 51, y: 50 },
+            { x: 97, y: 50 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_linek2NgvxH4Nd',
+      x: -554,
+      y: 294,
+      client: { x: -538, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -565, y: 313 },
+        tc: { x: -538, y: 313 },
+        tr: { x: -511, y: 313 },
+        l: { x: -565, y: 313 },
+        r: { x: -511, y: 313 },
+        bl: { x: -565, y: 313 },
+        bc: { x: -538, y: 313 },
+        br: { x: -511, y: 313 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 59, y: 51 },
+            { x: 103, y: 51 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_lineZu9slDCUUd',
+      x: -321,
+      y: 293,
+      client: { x: -321, y: 314 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -343.5, y: 314 },
+        tc: { x: -321, y: 314 },
+        tr: { x: -298.5, y: 314 },
+        l: { x: -343.5, y: 314 },
+        r: { x: -298.5, y: 314 },
+        bl: { x: -343.5, y: 314 },
+        bc: { x: -321, y: 314 },
+        br: { x: -298.5, y: 314 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 95, y: 50 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_linelZOGc5aG2N',
+      x: -375,
+      y: 292,
+      client: { x: -399, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -426, y: 313 },
+        tc: { x: -399, y: 313 },
+        tr: { x: -372, y: 313 },
+        l: { x: -426, y: 313 },
+        r: { x: -372, y: 313 },
+        bl: { x: -426, y: 313 },
+        bc: { x: -399, y: 313 },
+        br: { x: -372, y: 313 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 61, y: 51 },
+            { x: 103, y: 51 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_linePOFwnnzvAq',
+      x: -546,
+      y: 343,
+      client: { x: -546, y: 365 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -546.5, y: 342.5 },
+        tc: { x: -546, y: 342.5 },
+        tr: { x: -545.5, y: 342.5 },
+        l: { x: -546.5, y: 365 },
+        r: { x: -545.5, y: 365 },
+        bl: { x: -546.5, y: 387.5 },
+        bc: { x: -546, y: 387.5 },
+        br: { x: -545.5, y: 387.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 51, y: 32 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'electric-breakerfztlV6HGOI',
+      x: -568,
+      y: 375,
+      client: { x: -568, y: 393 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -590.0588989257812, y: 343.82001876831055 },
+        tc: { x: -568, y: 343.82001876831055 },
+        tr: { x: -545.9411010742188, y: 343.82001876831055 },
+        l: { x: -590.0588989257812, y: 393 },
+        r: { x: -545.9411010742188, y: 393 },
+        bl: { x: -590.0588989257812, y: 442.17998123168945 },
+        bc: { x: -568, y: 442.17998123168945 },
+        br: { x: -545.9411010742188, y: 442.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'connection_line26MoSsACzZ',
+      x: -456,
+      y: 343,
+      client: { x: -456, y: 365 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -456.5, y: 342.5 },
+        tc: { x: -456, y: 342.5 },
+        tr: { x: -455.5, y: 342.5 },
+        l: { x: -456.5, y: 365 },
+        r: { x: -455.5, y: 365 },
+        bl: { x: -456.5, y: 387.5 },
+        bc: { x: -456, y: 387.5 },
+        br: { x: -455.5, y: 387.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 33 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'electric-breakeraE7ngUn8TD',
+      x: -478,
+      y: 374,
+      client: { x: -478, y: 391 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -500.05889892578125, y: 341.82001876831055 },
+        tc: { x: -478, y: 341.82001876831055 },
+        tr: { x: -455.94110107421875, y: 341.82001876831055 },
+        l: { x: -500.05889892578125, y: 391 },
+        r: { x: -455.94110107421875, y: 391 },
+        bl: { x: -500.05889892578125, y: 440.17998123168945 },
+        bc: { x: -478, y: 440.17998123168945 },
+        br: { x: -455.94110107421875, y: 440.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器-copy',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'connection_lineibxBHM0S9F',
+      x: -364,
+      y: 339,
+      client: { x: -367, y: 363 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -367.5, y: 340.5 },
+        tc: { x: -367, y: 340.5 },
+        tr: { x: -366.5, y: 340.5 },
+        l: { x: -367.5, y: 363 },
+        r: { x: -366.5, y: 363 },
+        bl: { x: -367.5, y: 385.5 },
+        bc: { x: -367, y: 385.5 },
+        br: { x: -366.5, y: 385.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 36 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_lineJUvw4pt6ft',
+      x: -277,
+      y: 339,
+      client: { x: -277, y: 360 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -277.5, y: 337.5 },
+        tc: { x: -277, y: 337.5 },
+        tr: { x: -276.5, y: 337.5 },
+        l: { x: -277.5, y: 360 },
+        r: { x: -276.5, y: 360 },
+        bl: { x: -277.5, y: 382.5 },
+        bc: { x: -277, y: 382.5 },
+        br: { x: -276.5, y: 382.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 37 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'electric-breakerO6pjkUkcp7',
+      x: -386,
+      y: 376,
+      client: { x: -386, y: 392 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -408.05889892578125, y: 342.82001876831055 },
+        tc: { x: -386, y: 342.82001876831055 },
+        tr: { x: -363.94110107421875, y: 342.82001876831055 },
+        l: { x: -408.05889892578125, y: 392 },
+        r: { x: -363.94110107421875, y: 392 },
+        bl: { x: -408.05889892578125, y: 441.17998123168945 },
+        bc: { x: -386, y: 441.17998123168945 },
+        br: { x: -363.94110107421875, y: 441.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器-copy-copy',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'electric-breakerzbNanrnQvI',
+      x: -301,
+      y: 375,
+      client: { x: -301, y: 375 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -323.05889892578125, y: 325.82001876831055 },
+        tc: { x: -301, y: 325.82001876831055 },
+        tr: { x: -278.94110107421875, y: 325.82001876831055 },
+        l: { x: -323.05889892578125, y: 375 },
+        r: { x: -278.94110107421875, y: 375 },
+        bl: { x: -323.05889892578125, y: 424.17998123168945 },
+        bc: { x: -301, y: 424.17998123168945 },
+        br: { x: -278.94110107421875, y: 424.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器-copy-copy-copy',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-line5bLLa1fo6m',
+      x: -547,
+      y: 471,
+      client: { x: -547, y: 488 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -556.1135158538818, y: 440.05868911743164 },
+        tc: { x: -547, y: 440.05868911743164 },
+        tr: { x: -537.8864841461182, y: 440.05868911743164 },
+        l: { x: -556.1135158538818, y: 488 },
+        r: { x: -537.8864841461182, y: 488 },
+        bl: { x: -556.1135158538818, y: 535.9413108825684 },
+        bc: { x: -547, y: 535.9413108825684 },
+        br: { x: -537.8864841461182, y: 535.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-lineqPB3ix7BkL',
+      x: -457,
+      y: 472,
+      client: { x: -457, y: 472 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -466.11351585388184, y: 424.05868911743164 },
+        tc: { x: -457, y: 424.05868911743164 },
+        tr: { x: -447.88648414611816, y: 424.05868911743164 },
+        l: { x: -466.11351585388184, y: 472 },
+        r: { x: -447.88648414611816, y: 472 },
+        bl: { x: -466.11351585388184, y: 519.9413108825684 },
+        bc: { x: -457, y: 519.9413108825684 },
+        br: { x: -447.88648414611816, y: 519.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-lineBoydWOHHmr',
+      x: -366,
+      y: 471,
+      client: { x: -366, y: 471 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -375.11351585388184, y: 423.05868911743164 },
+        tc: { x: -366, y: 423.05868911743164 },
+        tr: { x: -356.88648414611816, y: 423.05868911743164 },
+        l: { x: -375.11351585388184, y: 471 },
+        r: { x: -356.88648414611816, y: 471 },
+        bl: { x: -375.11351585388184, y: 518.9413108825684 },
+        bc: { x: -366, y: 518.9413108825684 },
+        br: { x: -356.88648414611816, y: 518.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-line5waKsA7PHF',
+      x: -280,
+      y: 473,
+      client: { x: -282, y: 473 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -291.11351585388184, y: 425.05868911743164 },
+        tc: { x: -282, y: 425.05868911743164 },
+        tr: { x: -272.88648414611816, y: 425.05868911743164 },
+        l: { x: -291.11351585388184, y: 473 },
+        r: { x: -272.88648414611816, y: 473 },
+        bl: { x: -291.11351585388184, y: 520.9413108825684 },
+        bc: { x: -282, y: 520.9413108825684 },
+        br: { x: -272.88648414611816, y: 520.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy-copy-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text9mE6DlRsxq',
+      x: -662,
+      y: -63,
+      client: { x: -662, y: -63 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -700, y: -73 },
+        tc: { x: -662, y: -73 },
+        tr: { x: -624, y: -73 },
+        l: { x: -700, y: -63 },
+        r: { x: -624, y: -63 },
+        bl: { x: -700, y: -53 },
+        bc: { x: -662, y: -53 },
+        br: { x: -624, y: -53 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '备风机移变' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textffQAK2KK7l',
+      x: -512,
+      y: 313,
+      client: { x: -512, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -524.4000005722046, y: 297 },
+        tc: { x: -512, y: 297 },
+        tr: { x: -499.5999994277954, y: 297 },
+        l: { x: -524.4000005722046, y: 313 },
+        r: { x: -499.5999994277954, y: 313 },
+        bl: { x: -524.4000005722046, y: 329 },
+        bc: { x: -512, y: 329 },
+        br: { x: -499.5999994277954, y: 329 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '备' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 24 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00DDFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textErE3B1l7S1',
+      x: -334,
+      y: 312,
+      client: { x: -334, y: 312 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -346.4000005722046, y: 296 },
+        tc: { x: -334, y: 296 },
+        tr: { x: -321.5999994277954, y: 296 },
+        l: { x: -346.4000005722046, y: 312 },
+        r: { x: -321.5999994277954, y: 312 },
+        bl: { x: -346.4000005722046, y: 328 },
+        bc: { x: -334, y: 328 },
+        br: { x: -321.5999994277954, y: 328 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '主' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 24 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00DDFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textIjsFbs6fID',
+      x: -675,
+      y: -172,
+      client: { x: -675, y: -172 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -782.466552734375, y: -182 },
+        tc: { x: -675, y: -182 },
+        tr: { x: -567.533447265625, y: -182 },
+        l: { x: -782.466552734375, y: -172 },
+        r: { x: -567.533447265625, y: -172 },
+        bl: { x: -782.466552734375, y: -162 },
+        bc: { x: -675, y: -162 },
+        br: { x: -567.533447265625, y: -162 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '来在12煤三盘区变电所G1211柜' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textWilG5jRH7w',
+      x: -353,
+      y: -172,
+      client: { x: -353, y: -172 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -460.466552734375, y: -182 },
+        tc: { x: -353, y: -182 },
+        tr: { x: -245.533447265625, y: -182 },
+        l: { x: -460.466552734375, y: -172 },
+        r: { x: -245.533447265625, y: -172 },
+        bl: { x: -460.466552734375, y: -162 },
+        bc: { x: -353, y: -162 },
+        br: { x: -245.533447265625, y: -162 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '来在12煤三盘区变电所G1107柜' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textcxjU8wN810',
+      x: -137,
+      y: 553,
+      client: { x: -137, y: 553 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -152.5, y: 543 },
+        tc: { x: -137, y: 543 },
+        tr: { x: -121.5, y: 543 },
+        l: { x: -152.5, y: 553 },
+        r: { x: -121.5, y: 553 },
+        bl: { x: -152.5, y: 563 },
+        bc: { x: -137, y: 563 },
+        br: { x: -121.5, y: 563 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '主风机馈电' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textHXkhPmUMWE',
+      x: -742,
+      y: 551,
+      client: { x: -742, y: 551 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -779.6000022888184, y: 541 },
+        tc: { x: -742, y: 541 },
+        tr: { x: -704.3999977111816, y: 541 },
+        l: { x: -779.6000022888184, y: 551 },
+        r: { x: -704.3999977111816, y: 551 },
+        bl: { x: -779.6000022888184, y: 561 },
+        bc: { x: -742, y: 561 },
+        br: { x: -704.3999977111816, y: 561 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '备风机馈电' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textH6apeUpS25',
+      x: -280,
+      y: -100,
+      client: { x: -280, y: -100 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -325.5, y: -110 },
+        tc: { x: -280, y: -110 },
+        tr: { x: -234.5, y: -110 },
+        l: { x: -325.5, y: -100 },
+        r: { x: -234.5, y: -100 },
+        bl: { x: -325.5, y: -90 },
+        bc: { x: -280, y: -90 },
+        br: { x: -234.5, y: -90 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '高压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textdlSMN5CrsK',
+      x: -281,
+      y: 127,
+      client: { x: -281, y: 127 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -326.5, y: 117 },
+        tc: { x: -281, y: 117 },
+        tr: { x: -235.5, y: 117 },
+        l: { x: -326.5, y: 127 },
+        r: { x: -235.5, y: 127 },
+        bl: { x: -326.5, y: 137 },
+        bc: { x: -281, y: 137 },
+        br: { x: -235.5, y: 137 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '低压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text8hfqYu7qCf',
+      x: -838,
+      y: 127,
+      client: { x: -838, y: 127 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -883.5, y: 117 },
+        tc: { x: -838, y: 117 },
+        tr: { x: -792.5, y: 117 },
+        l: { x: -883.5, y: 127 },
+        r: { x: -792.5, y: 127 },
+        bl: { x: -883.5, y: 137 },
+        bc: { x: -838, y: 137 },
+        br: { x: -792.5, y: 137 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '低压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textYN6br3c8mY',
+      x: -835,
+      y: -100,
+      client: { x: -835, y: -105 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -880.5, y: -115 },
+        tc: { x: -835, y: -115 },
+        tr: { x: -789.5, y: -115 },
+        l: { x: -880.5, y: -105 },
+        r: { x: -789.5, y: -105 },
+        bl: { x: -880.5, y: -95 },
+        bc: { x: -835, y: -95 },
+        br: { x: -789.5, y: -95 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy-copy-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '高压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text9OtB4BD8tx',
+      x: -811,
+      y: -75,
+      client: { x: -811, y: -78 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -826.1000003814697, y: -88 },
+        tc: { x: -811, y: -88 },
+        tr: { x: -795.8999996185303, y: -88 },
+        l: { x: -826.1000003814697, y: -78 },
+        r: { x: -795.8999996185303, y: -78 },
+        bl: { x: -826.1000003814697, y: -68 },
+        bc: { x: -811, y: -68 },
+        br: { x: -795.8999996185303, y: -68 },
+      },
+      name: 'custom-svg-text',
+      title: 'b-state',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textifb0BW0nZX',
+      x: -252,
+      y: -74,
+      client: { x: -252, y: -74 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -267.1000003814697, y: -84 },
+        tc: { x: -252, y: -84 },
+        tr: { x: -236.89999961853027, y: -84 },
+        l: { x: -267.1000003814697, y: -74 },
+        r: { x: -236.89999961853027, y: -74 },
+        bl: { x: -267.1000003814697, y: -64 },
+        bc: { x: -252, y: -64 },
+        br: { x: -236.89999961853027, y: -64 },
+      },
+      name: 'custom-svg-text',
+      title: 'z-state',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineFGURWExYla',
+      x: -811,
+      y: -88,
+      client: { x: 347, y: 258 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -811, y: -88 },
+        tc: { x: -811, y: -88 },
+        tr: { x: -811, y: -88 },
+        l: { x: -811, y: -88 },
+        r: { x: -811, y: -88 },
+        bl: { x: -811, y: -88 },
+        bc: { x: -811, y: -88 },
+        br: { x: -811, y: -88 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: { title: '点坐标', type: 'JsonEdit', val: [{ x: 50, y: 50 }] },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text9OtB4BD8tx' }, end: null },
+    },
+    {
+      id: 'custom-svg-textlqc2YZTzyI',
+      x: -815,
+      y: 153,
+      client: { x: -815, y: 153 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -830.1000003814697, y: 143 },
+        tc: { x: -815, y: 143 },
+        tr: { x: -799.8999996185303, y: 143 },
+        l: { x: -830.1000003814697, y: 153 },
+        r: { x: -799.8999996185303, y: 153 },
+        bl: { x: -830.1000003814697, y: 163 },
+        bc: { x: -815, y: 163 },
+        br: { x: -799.8999996185303, y: 163 },
+      },
+      name: 'custom-svg-text',
+      title: 'b-state1',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textwo1kl0CsXG',
+      x: -249,
+      y: 151,
+      client: { x: -249, y: 151 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -264.1000003814697, y: 141 },
+        tc: { x: -249, y: 141 },
+        tr: { x: -233.89999961853027, y: 141 },
+        l: { x: -264.1000003814697, y: 151 },
+        r: { x: -233.89999961853027, y: 151 },
+        bl: { x: -264.1000003814697, y: 161 },
+        bc: { x: -249, y: 161 },
+        br: { x: -233.89999961853027, y: 161 },
+      },
+      name: 'custom-svg-text',
+      title: 'z-state1',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+  ],
+});
+
+export const option = reactive<EChartsOption>({
+  title: {
+    text: '局部通风机运行工况智能决策',
+    textStyle: {
+      color: '#BF954D',
+    },
+    left: 'center',
+    top: 0,
+  },
+  // backgroundColor: '#39deff',
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross',
+      label: {
+        backgroundColor: '#6a7985',
+      },
+    },
+  },
+  toolbox: {
+    show: true,
+  },
+  grid: {
+    left: 8,
+    right: 50,
+    bottom: 0,
+    containLabel: true,
+  },
+  xAxis: {
+    type: 'category',
+    name: 'm³/min',
+    nameTextStyle: {
+      fontWeight: 600,
+      fontSize: 13,
+    },
+    splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+    axisLabel: {
+      margin: 10,
+      fontSize: 14,
+      color: '#f1f1f199',
+    },
+    boundaryGap: false,
+    data: [],
+  },
+  yAxis: {
+    type: 'value',
+    axisLine: {
+      show: true,
+      lineStyle: {
+        color: '#006c9d',
+      },
+    },
+    splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+    axisLabel: {
+      show: true,
+      fontSize: 14,
+      formatter: '{value}',
+      color: '#0071A5',
+    },
+    min: 1000,
+    max: 9000,
+    name: 'Pa',
+    nameTextStyle: {
+      fontWeight: 600,
+      fontSize: 13,
+    },
+  },
+  series: [],
+});
+export const echatsOption = {
+  grid: {
+    top: '15%',
+    left: '20',
+    right: '45',
+    bottom: '0',
+    containLabel: true,
+  },
+  toolbox: {
+    feature: null,
+  },
+  legend: {
+    top: -10,
+  },
+};
+
+export const chartsColumnList = [
+  {
+    legend: '瓦斯浓度',
+    seriesName: '(%)',
+    ymax: 0.8,
+    yname: '%',
+    linetype: 'line',
+    yaxispos: 'left',
+    color: '#00FFA8',
+    sort: 1,
+    xRotate: 0,
+    dataIndex: 'gas',
+  },
+  {
+    legend: '风量',
+    seriesName: '(m³/min)',
+    ymax: 1100,
+    yname: 'm³/min',
+    linetype: 'line',
+    yaxispos: 'right',
+    color: '#FDB146',
+    sort: 2,
+    xRotate: 0,
+    dataIndex: 'm3',
+  },
+  {
+    legend: '频率',
+    seriesName: '(Hz)',
+    ymax: 50,
+    yname: 'Hz',
+    linetype: 'line',
+    yaxispos: 'right',
+    color: '#AE19FF',
+    sort: 3,
+    xRotate: 0,
+    dataIndex: 'Hz',
+  },
+];
+
+export const initData = () => {
+  const num = 20;
+  const obj = {
+    angle: 0,
+    Hz: 50.0,
+    a: -0.0354466316912028,
+    b: 46.9032472840413,
+    c: -6837.67023286905,
+    min: 600,
+    max: 1100.0,
+  };
+  const a = -0.0354,
+    m = 46.90324,
+    n = -6837.67023;
+  const data = [];
+  for (let i = 0; i <= num; i++) {
+    const item = cloneDeep(obj);
+    const maxn = 14 * i - 0.15 * i * i;
+    item['a'] = Math.round((a - 0.02 * 0.02 * i) * 10000) / 10000;
+    item['Hz'] = 50 - i;
+    item['c'] = n - 10 * i - 0.0232 * i * i;
+    item['b'] = m + i * 0.31 * 0.12;
+    item['max'] = 1090.0 - maxn;
+    item['min'] = 600 + 0.2 * (i - 50) * i;
+    data.push(item);
+  }
+  console.log('------------------->', data);
+  return data;
+};
+
+export const fanInfoData = reactive({
+  fj: '一号回风井',
+  xh: 'FBCDZ No.29',
+  gl: '2×500',
+  edgl: '740',
+  eddy: '10000',
+  eddl: '38.4',
+  flfw: '110~260',
+  fyfw: '200~4100',
+  fbdj: 'ExdI',
+  ccrq: '2010.07',
+  sccj: '南阳防爆',
+  tjfs: '变频调节',
+  plfw: '30~50',
+});
+
+export const fanInfo = [
+  {
+    title: '风井',
+    code: 'fj',
+    value: '一号回风井',
+  },
+  {
+    title: '型号',
+    code: 'xh',
+    value: 'FBCDZ No.29',
+  },
+  {
+    title: '功率(kW)',
+    code: 'gl',
+    value: '2×500',
+  },
+  {
+    title: '额定转速(r/min)',
+    code: 'edgl',
+    value: '740',
+  },
+  {
+    title: '额定电压(V)',
+    code: 'eddy',
+    value: '10000',
+  },
+  {
+    title: '额定电流(A)',
+    code: 'eddl',
+    value: '38.4',
+  },
+  {
+    title: '风量范围(m³/s)',
+    code: 'flfw',
+    value: '110~260',
+  },
+  {
+    title: '风压范围(Pa)',
+    code: 'fyfw',
+    value: '200~4100',
+  },
+  {
+    title: '防爆等级',
+    code: 'fbdj',
+    value: 'ExdI',
+  },
+  {
+    title: '出厂日期',
+    code: 'ccrq',
+    value: '2010.07',
+  },
+  {
+    title: '生产厂家',
+    code: 'sccj',
+    value: '南阳防爆',
+  },
+  {
+    title: '调节方式',
+    code: 'tjfs',
+    value: '变频调节',
+  },
+  {
+    title: '频率可调范围(Hz)',
+    code: 'plfw',
+    value: '30~50',
+  },
+];
+
+export const getSchamas = (): FormSchema[] => {
+  return [
+    {
+      field: 'fj',
+      component: 'Input',
+      label: '风井',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'xh',
+      component: 'Input',
+      label: '型号',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'gl',
+      component: 'Input',
+      label: '功率(kW)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'edgl',
+      component: 'Input',
+      label: '额定转速(r/min)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'eddy',
+      component: 'Input',
+      label: '额定电压(V)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'eddl',
+      component: 'Input',
+      label: '额定电流(A)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'flfw',
+      component: 'Input',
+      label: '风量范围(m³/s)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'fyfw',
+      component: 'Input',
+      label: '风压范围(Pa)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'fbdj',
+      component: 'Select',
+      label: '防爆等级',
+      colProps: {
+        span: 6,
+      },
+      componentProps: {
+        options: [
+          {
+            label: 'ExdI',
+            value: 'ExdI',
+            key: '1',
+          },
+        ],
+      },
+    },
+    {
+      field: 'ccrq',
+      component: 'Input',
+      label: '出厂日期',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'sccj',
+      component: 'Input',
+      label: '生产厂家',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'tjfs',
+      component: 'Select',
+      label: '调节方式',
+      colProps: {
+        span: 6,
+      },
+      componentProps: {
+        options: [
+          {
+            label: '变频调节',
+            value: '变频调节',
+            key: '1',
+          },
+        ],
+      },
+    },
+    {
+      field: 'plfw',
+      component: 'Input',
+      label: '频率可调范围(Hz)',
+      colProps: {
+        span: 6,
+      },
+    },
+  ];
+};
+
+export const getSchamas1 = (): FormSchema[] => {
+  return [
+    {
+      field: 'Hz',
+      component: 'InputNumber',
+      label: '频率(Hz)',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'a',
+      component: 'InputNumber',
+      label: '二次项系数',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'b',
+      component: 'InputNumber',
+      label: '一次项系数',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'c',
+      component: 'InputNumber',
+      label: '常数项系数',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'min',
+      component: 'InputNumber',
+      label: '风量下限(m³/s)',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'max',
+      component: 'InputNumber',
+      label: '风量上限(m³/s)',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+  ];
+};
+
+export const lineFormData = reactive({
+  Hz: null,
+  a: null,
+  b: null,
+  c: null,
+  min: null,
+  max: null,
+});

+ 3961 - 0
src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.data2.ts

@@ -0,0 +1,3961 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { rules } from '/@/utils/helper/validator';
+import { ref, reactive } from 'vue';
+import { cloneDeep } from 'lodash-es';
+export const columns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 120,
+  },
+  {
+    title: '安装位置',
+    dataIndex: 'strinstallpos',
+    width: 100,
+  },
+  {
+    title: '是否为常闭型',
+    dataIndex: 'bnormalclose',
+    width: 100,
+    // customRender: render.renderAvatar,
+  },
+  {
+    title: '净宽',
+    dataIndex: 'fclearwidth',
+    width: 80,
+  },
+  {
+    title: '净高',
+    dataIndex: 'fclearheight',
+    width: 100,
+  },
+  {
+    title: '风门道数',
+    dataIndex: 'ndoorcount',
+    width: 100,
+  },
+  {
+    title: '所属分站',
+    width: 150,
+    dataIndex: 'stationname',
+  },
+  {
+    title: '点表',
+    width: 100,
+    dataIndex: 'strtype',
+  },
+  {
+    title: '监测类型',
+    dataIndex: 'monitorflag',
+    width: 100,
+  },
+  {
+    title: '是否模拟数据',
+    dataIndex: 'testflag',
+    width: 100,
+  },
+];
+
+export const recycleColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+  },
+  {
+    title: '是否为常闭型',
+    dataIndex: 'bnormalclose',
+    width: 100,
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '名称',
+    field: 'strname',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '安装位置',
+    field: 'strinstallpos',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '是否为常闭型',
+    field: 'bnormalclose',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择读写类型',
+      stringToNumber: true,
+    },
+    colProps: { span: 6 },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '名称',
+    field: 'strname',
+    component: 'Input',
+  },
+  {
+    label: '安装位置',
+    field: 'strinstallpos',
+    component: 'Input',
+  },
+  {
+    label: '是否为常闭型',
+    field: 'bnormalclose',
+    component: 'RadioGroup',
+    defaultValue: 1,
+    componentProps: () => {
+      return {
+        options: [
+          { label: '是', value: 1, key: '1' },
+          { label: '否', value: 0, key: '2' },
+        ],
+      };
+    },
+  },
+  {
+    label: '净宽',
+    field: 'fclearwidth',
+    component: 'Input',
+  },
+  {
+    label: '净高',
+    field: 'fclearheight',
+    component: 'Input',
+  },
+  {
+    label: '风门道数',
+    field: 'ndoorcount',
+    component: 'Input',
+  },
+  {
+    label: '所属分站',
+    field: 'stationname',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择状态',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '点表',
+    field: 'strtype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择状态',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '监测类型',
+    field: 'monitorflag',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'user_status',
+      placeholder: '请选择状态',
+      stringToNumber: true,
+    },
+  },
+  {
+    label: '是否模拟数据',
+    field: 'testflag',
+    component: 'RadioGroup',
+    defaultValue: 1,
+    componentProps: () => {
+      return {
+        options: [
+          { label: '是', value: 1, key: '1' },
+          { label: '否', value: 0, key: '2' },
+        ],
+      };
+    },
+  },
+];
+
+export const formPasswordSchema: FormSchema[] = [
+  {
+    label: '用户账号',
+    field: 'username',
+    component: 'Input',
+    componentProps: { readOnly: true },
+  },
+  {
+    label: '登录密码',
+    field: 'password',
+    component: 'StrengthMeter',
+    componentProps: {
+      placeholder: '请输入登录密码',
+    },
+    rules: [
+      {
+        required: true,
+        message: '请输入登录密码',
+      },
+    ],
+  },
+  {
+    label: '确认密码',
+    field: 'confirmPassword',
+    component: 'InputPassword',
+    dynamicRules: ({ values }) => rules.confirmPassword(values, true),
+  },
+];
+
+export const formAgentSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    field: 'userName',
+    label: '用户名',
+    component: 'Input',
+    componentProps: {
+      readOnly: true,
+      allowClear: false,
+    },
+  },
+  {
+    field: 'agentUserName',
+    label: '代理人用户名',
+    required: true,
+    component: 'JSelectUser',
+    componentProps: {
+      rowKey: 'username',
+      labelKey: 'realname',
+      maxSelectCount: 10,
+    },
+  },
+  {
+    field: 'startTime',
+    label: '代理开始时间',
+    component: 'DatePicker',
+    required: true,
+    componentProps: {
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      placeholder: '请选择代理开始时间',
+    },
+  },
+  {
+    field: 'endTime',
+    label: '代理结束时间',
+    component: 'DatePicker',
+    required: true,
+    componentProps: {
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      placeholder: '请选择代理结束时间',
+    },
+  },
+  {
+    field: 'status',
+    label: '状态',
+    component: 'JDictSelectTag',
+    defaultValue: '1',
+    componentProps: {
+      dictCode: 'valid_status',
+      type: 'radioButton',
+    },
+  },
+];
+
+export const chartsColumns = [
+  {
+    legend: '瓦斯浓度',
+    seriesName: '瓦斯浓度(%)',
+    ymax: 100,
+    yname: '%',
+    linetype: 'bar',
+    yaxispos: 'left',
+    color: '#cd5fff',
+    sort: 1,
+    dataIndex: '',
+    xRotate: 0,
+  },
+];
+export const chartsColumns1 = [
+  {
+    legend: '风量',
+    seriesName: 'm³/min',
+    ymax: 1000,
+    yname: '',
+    linetype: 'bar',
+    yaxispos: 'left',
+    color: '#755cf8',
+    sort: 1,
+    dataIndex: '',
+    xRotate: 0,
+  },
+];
+
+export const transformMobileH = [
+  {
+    title: 'A相电流(A)',
+    code: '',
+  },
+  {
+    title: 'B相电流(A)',
+    code: '',
+  },
+  {
+    title: 'C相电流(A)',
+    code: '',
+  },
+  {
+    title: '电压(V)',
+    code: '',
+  },
+  {
+    title: '温度(℃)',
+    code: '',
+  },
+  {
+    title: '额定电流(A)',
+    code: '',
+  },
+  {
+    title: '短路电流(A)',
+    code: '',
+  },
+];
+
+export const transformMobileL = [
+  {
+    title: 'A相电流(A)',
+    code: '',
+  },
+  {
+    title: 'B相电流(A)',
+    code: '',
+  },
+  {
+    title: 'C相电流(A)',
+    code: '',
+  },
+  {
+    title: '电压(V)',
+    code: '',
+  },
+  {
+    title: '功率(KW)',
+    code: '',
+  },
+  {
+    title: '额定电流(A)',
+    code: '',
+  },
+  {
+    title: '短路电流(A)',
+    code: '',
+  },
+];
+
+export const protectionEnableH = [
+  {
+    title: '短路',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '不平衡',
+    code: '',
+    value: '未使能',
+  },
+  {
+    title: '过载',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '过压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '欠压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '短路延时(ms)',
+    code: '',
+    value: 0,
+  },
+  {
+    title: '过压延时(s)',
+    code: '',
+    value: 10,
+  },
+  {
+    title: '欠压延时(s)',
+    code: '',
+    value: 10,
+  },
+];
+
+export const protectionEnableL = [
+  {
+    title: '短路',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '不平衡',
+    code: '',
+    value: '未使能',
+  },
+  {
+    title: '过载',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '过压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '欠压',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '漏电',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '漏电闭锁',
+    code: '',
+    value: '使能',
+  },
+  {
+    title: '漏电延时(ms)',
+    code: '',
+    value: 10,
+  },
+  {
+    title: '短路延时(ms)',
+    code: '',
+    value: 1,
+  },
+  {
+    title: '过压延时(s)',
+    code: '',
+    value: 10,
+  },
+  {
+    title: '欠压延时(s)',
+    code: '',
+    value: 10,
+  },
+];
+
+export const electricMonitor = {
+  电流: [
+    {
+      title: 'A相电流 (A)',
+      code: '',
+    },
+    {
+      title: 'B相电流 (A)',
+      code: '',
+    },
+    {
+      title: 'C相电流 (A)',
+      code: '',
+    },
+    {
+      title: '额定电流 (A)',
+      code: '',
+    },
+  ],
+  电压: [
+    {
+      title: 'Uac (V)',
+      code: '',
+    },
+    {
+      title: '功率 (KW)',
+      code: '',
+    },
+  ],
+  保护状态: [
+    {
+      title: '短路',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '失压',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '过载',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '过压',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '缺相',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '漏电保护',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '相不平衡',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '漏电闭锁',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '瓦斯闭锁',
+      code: '',
+      value: 1,
+    },
+    {
+      title: '选择性漏电保护',
+      code: '',
+      value: 1,
+    },
+  ],
+};
+
+export const electricState = [
+  {
+    title: '额定电流(A)',
+    code: '',
+    value: 100.0,
+  },
+  {
+    title: '额定电压(V)',
+    code: '',
+    value: 660,
+  },
+  {
+    title: '短路倍数',
+    code: '',
+    value: 8,
+  },
+  {
+    title: '欠压倍数',
+    code: '',
+    value: 0.85,
+  },
+  {
+    title: '漏电延时(s)',
+    code: '',
+    value: 5.0,
+  },
+  {
+    title: '不平衡倍数',
+    code: '',
+    value: 0.0,
+  },
+  {
+    title: '漏电闭锁(KΩ)',
+    code: '',
+    value: 11,
+  },
+  {
+    title: '末端短路倍数',
+    code: '',
+    value: 1.0,
+  },
+  {
+    title: '相敏倍数',
+    code: '',
+    value: 41.0,
+  },
+  {
+    title: '过压延时(s)',
+    code: '',
+    value: 1.2,
+  },
+  {
+    title: '过压定值',
+    code: '',
+    value: 1.2,
+  },
+];
+
+export const fanControlState1 = {
+  电流电压: {
+    'la1(A)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+    'lb1(A)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+    'lc1(A)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+    '额定电流(A)': [
+      {
+        code: '',
+        value: 55.0,
+      },
+      {
+        code: '',
+        value: 55.0,
+      },
+    ],
+    'Uac(V)': [
+      {
+        code: '',
+        value: 658,
+      },
+    ],
+  },
+  功率: {
+    '功率(KW)': [
+      {
+        code: '',
+        value: 0.0,
+      },
+      {
+        code: '',
+        value: 0.0,
+      },
+    ],
+  },
+  运行状态: {
+    开合闸状态: [
+      {
+        code: '',
+        value: 0,
+      },
+      {
+        code: '',
+        value: 0,
+      },
+    ],
+  },
+};
+export const fanControlState2 = {
+  电流电压: {
+    'la1(A)': [
+      {
+        code: '',
+        value: 35.0,
+      },
+      {
+        code: '',
+        value: 28.0,
+      },
+    ],
+    'lb1(A)': [
+      {
+        code: '',
+        value: 34.0,
+      },
+      {
+        code: '',
+        value: 28.0,
+      },
+    ],
+    'lc1(A)': [
+      {
+        code: '',
+        value: 34.0,
+      },
+      {
+        code: '',
+        value: 29.0,
+      },
+    ],
+    '额定电流(A)': [
+      {
+        code: '',
+        value: 75.0,
+      },
+      {
+        code: '',
+        value: 75.0,
+      },
+    ],
+    'Uac(V)': [
+      {
+        code: '',
+        value: 697,
+      },
+    ],
+  },
+  功率: {
+    '功率(KW)': [
+      {
+        code: '',
+        value: 42,
+      },
+      {
+        code: '',
+        value: 34,
+      },
+    ],
+  },
+  运行状态: {
+    开合闸状态: [
+      {
+        code: '',
+        value: 1,
+      },
+      {
+        code: '',
+        value: 1,
+      },
+    ],
+  },
+};
+
+export const fanSetting1 = [
+  {
+    title: 'I额定电流(A)',
+    code: '',
+    value: '55',
+  },
+  {
+    title: 'II额定电流(A)',
+    code: '',
+    value: '55',
+  },
+  {
+    title: '电压等级(V)',
+    code: '',
+    value: '660',
+  },
+  {
+    title: 'I速断定值',
+    code: '',
+    value: '8',
+  },
+  {
+    title: 'II速断定值',
+    code: '',
+    value: '8',
+  },
+  {
+    title: '欠压定值',
+    code: '',
+    value: '1',
+  },
+  {
+    title: '欠压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: '过压定值',
+    code: '',
+    value: '1',
+  },
+  {
+    title: '过压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: 'I启动II延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '启动对侧延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '风电瓦斯延时(s)',
+    code: '',
+    value: '0',
+  },
+];
+
+export const fanSetting2 = [
+  {
+    title: 'I额定电流(A)',
+    code: '',
+    value: '75',
+  },
+  {
+    title: 'II额定电流(A)',
+    code: '',
+    value: '75',
+  },
+  {
+    title: '电压等级(V)',
+    code: '',
+    value: '660',
+  },
+  {
+    title: 'I速断定值',
+    code: '',
+    value: '8',
+  },
+  {
+    title: 'II速断定值',
+    code: '',
+    value: '9',
+  },
+  {
+    title: '欠压定值',
+    code: '',
+    value: '0',
+  },
+  {
+    title: '欠压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: '过压定值',
+    code: '',
+    value: '1',
+  },
+  {
+    title: '过压延时',
+    code: '',
+    value: '6',
+  },
+  {
+    title: 'I启动II延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '启动对侧延时(s)',
+    code: '',
+    value: '5',
+  },
+  {
+    title: '风电瓦斯延时(s)',
+    code: '',
+    value: '0',
+  },
+];
+
+export const data_model = ref<any>({
+  layout_center: { x: 727, y: 226 },
+  config: {
+    background_color: '#00000000',
+    scale: 0.9,
+    position_center: { x: 0, y: 0 },
+    svg_position_center: { x: 50, y: 50 },
+    grid: true,
+    ruler: false,
+  },
+  done_json: [
+    {
+      id: 'connection_lineSAVIxZbu1U',
+      x: -322,
+      y: 297,
+      client: { x: -345, y: 316 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -345.5, y: 292 },
+        tc: { x: -345, y: 292 },
+        tr: { x: -344.5, y: 292 },
+        l: { x: -345.5, y: 316 },
+        r: { x: -344.5, y: 316 },
+        bl: { x: -345.5, y: 340 },
+        bc: { x: -345, y: 340 },
+        br: { x: -344.5, y: 340 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 47 },
+            { x: 50, y: 20 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_lineYOym7m1COw',
+      x: -499,
+      y: 293,
+      client: { x: -499, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -499.5, y: 289 },
+        tc: { x: -499, y: 289 },
+        tr: { x: -498.5, y: 289 },
+        l: { x: -499.5, y: 313 },
+        r: { x: -498.5, y: 313 },
+        bl: { x: -499.5, y: 337 },
+        bc: { x: -499, y: 337 },
+        br: { x: -498.5, y: 337 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 51, y: 53 },
+            { x: 51, y: 21 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'arrowWVIq74qgBO',
+      x: -520.5,
+      y: -143,
+      client: { x: -520.5, y: -143 },
+      scale_x: 0.45,
+      scale_y: 0.44799998632812543,
+      rotate: 179.9812559818536,
+      actual_bound: { x: 0.0000014901161193847656, y: 14.285714149475098, width: 100, height: 71.42857360839844 },
+      point_coordinate: {
+        tl: { x: -497.9947668868031, y: -127.00736161477208 },
+        tc: { x: -520.494765682786, y: -127.00000085618991 },
+        tr: { x: -542.994764478769, y: -126.99264009760776 },
+        l: { x: -498.00000120401705, y: -143.00736075858217 },
+        r: { x: -542.999998795983, y: -142.99263924141783 },
+        bl: { x: -498.00523552123104, y: -159.00735990239224 },
+        bc: { x: -520.505234317214, y: -158.99999914381007 },
+        br: { x: -543.0052331131969, y: -158.99263838522793 },
+      },
+      name: 'arrow',
+      title: '箭头',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrowUFvMb6HR6G',
+      x: -298.5,
+      y: -142,
+      client: { x: -302.5, y: -142 },
+      scale_x: 0.45,
+      scale_y: 0.44799998632812543,
+      rotate: 0,
+      actual_bound: { x: 0.0000014901161193847656, y: 14.285714149475098, width: 100, height: 71.42857360839844 },
+      point_coordinate: {
+        tl: { x: -325, y: -158 },
+        tc: { x: -302.5, y: -158 },
+        tr: { x: -280, y: -158 },
+        l: { x: -325, y: -142 },
+        r: { x: -280, y: -142 },
+        bl: { x: -325, y: -126 },
+        bc: { x: -302.5, y: -126 },
+        br: { x: -280, y: -126 },
+      },
+      name: 'arrow',
+      title: '箭头-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineTy3uyr5DOv',
+      x: 508,
+      y: 177,
+      client: { x: 508, y: 177 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -551.999998795983, y: -137.99263924141783 },
+        tc: { x: -551.999998795983, y: -137.99263924141783 },
+        tr: { x: -551.999998795983, y: -137.99263924141783 },
+        l: { x: -551.999998795983, y: -137.99263924141783 },
+        r: { x: -551.999998795983, y: -137.99263924141783 },
+        bl: { x: -551.999998795983, y: -137.99263924141783 },
+        bc: { x: -551.999998795983, y: -137.99263924141783 },
+        br: { x: -551.999998795983, y: -137.99263924141783 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: { title: '点坐标', type: 'JsonEdit', val: [{ x: 50, y: 50 }] },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'Right', target_id: 'arrowWVIq74qgBO' }, end: null },
+    },
+    {
+      id: 'rect3OD1llFsFbQ',
+      x: -688,
+      y: -224.5,
+      client: { x: -688, y: -224.5 },
+      scale_x: 1.9694118000598109,
+      scale_y: 0.3599999890136722,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -781, y: -227 },
+        tc: { x: -688, y: -227 },
+        tr: { x: -595, y: -227 },
+        l: { x: -781, y: -224.5 },
+        r: { x: -595, y: -224.5 },
+        bl: { x: -781, y: -222 },
+        bc: { x: -688, y: -222 },
+        br: { x: -595, y: -222 },
+      },
+      name: 'rect3',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect3z6ep3DMpbX',
+      x: -138,
+      y: -226.5,
+      client: { x: -138, y: -226.5 },
+      scale_x: 1.9694118000598109,
+      scale_y: 0.3599999890136722,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -231, y: -229 },
+        tc: { x: -138, y: -229 },
+        tr: { x: -45, y: -229 },
+        l: { x: -231, y: -226.5 },
+        r: { x: -45, y: -226.5 },
+        bl: { x: -231, y: -224 },
+        bc: { x: -138, y: -224 },
+        br: { x: -45, y: -224 },
+      },
+      name: 'rect3',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { fill: { title: '填充色', type: 'Color', val: '#ff0000' } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineYTEQVhroc2',
+      x: -542.999998795983,
+      y: -142.99263924141783,
+      client: { x: 588, y: 224 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -585.999998795983, y: -185.99263924141783 },
+        tc: { x: -542.999998795983, y: -185.99263924141783 },
+        tr: { x: -499.99999879598295, y: -185.99263924141783 },
+        l: { x: -585.999998795983, y: -142.99263924141783 },
+        r: { x: -499.99999879598295, y: -142.99263924141783 },
+        bl: { x: -585.999998795983, y: -99.99263924141783 },
+        bc: { x: -542.999998795983, y: -99.99263924141783 },
+        br: { x: -499.99999879598295, y: -99.99263924141783 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: -36, y: 51 },
+            { x: -36, y: -35 },
+            { x: -34, y: -34 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'Right', target_id: 'arrowWVIq74qgBO' }, end: null },
+    },
+    {
+      id: 'connection_lineHE0iHAc7sh',
+      x: -107.99999879598295,
+      y: -139.99263924141783,
+      client: { x: -107.99999879598295, y: -139.99263924141783 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -150.99999879598295, y: -182.99263924141783 },
+        tc: { x: -107.99999879598295, y: -182.99263924141783 },
+        tr: { x: -64.99999879598295, y: -182.99263924141783 },
+        l: { x: -150.99999879598295, y: -139.99263924141783 },
+        r: { x: -64.99999879598295, y: -139.99263924141783 },
+        bl: { x: -150.99999879598295, y: -96.99263924141783 },
+        bc: { x: -107.99999879598295, y: -96.99263924141783 },
+        br: { x: -64.99999879598295, y: -96.99263924141783 },
+      },
+      name: 'connection_line',
+      title: '连接线-copy',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: -124, y: 49 },
+            { x: -35, y: 49 },
+            { x: -36, y: -35 },
+            { x: -34, y: -34 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'Right', target_id: 'arrowWVIq74qgBO' }, end: null },
+    },
+    {
+      id: 'straight-lineGewWfZACIy',
+      x: -688,
+      y: -222,
+      client: { x: 452, y: 146 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -688.5, y: -284 },
+        tc: { x: -688, y: -284 },
+        tr: { x: -687.5, y: -284 },
+        l: { x: -688.5, y: -222 },
+        r: { x: -687.5, y: -222 },
+        bl: { x: -688.5, y: -160 },
+        bc: { x: -688, y: -160 },
+        br: { x: -687.5, y: -160 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 49, y: 174 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect3OD1llFsFbQ' }, end: null },
+    },
+    {
+      id: 'connection_linekOe9aqybJ7',
+      x: -132,
+      y: -227,
+      client: { x: -132, y: -227 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -132.5, y: -289 },
+        tc: { x: -132, y: -289 },
+        tr: { x: -131.5, y: -289 },
+        l: { x: -132.5, y: -227 },
+        r: { x: -131.5, y: -227 },
+        bl: { x: -132.5, y: -165 },
+        bc: { x: -132, y: -165 },
+        br: { x: -131.5, y: -165 },
+      },
+      name: 'connection_line',
+      title: '连接线-copy',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 50, y: 180 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect3OD1llFsFbQ' }, end: null },
+    },
+    {
+      id: 'rect1u3AJvpzHYv',
+      x: -689.5,
+      y: -63,
+      client: { x: -689.5, y: -63 },
+      scale_x: 0.7082353259023925,
+      scale_y: 0.7259259095159254,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -711, y: -98 },
+        tc: { x: -689.5, y: -98 },
+        tr: { x: -668, y: -98 },
+        l: { x: -711, y: -63 },
+        r: { x: -668, y: -63 },
+        bl: { x: -711, y: -28 },
+        bc: { x: -689.5, y: -28 },
+        br: { x: -668, y: -28 },
+      },
+      name: 'rect1',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#ff0000', closeVal: '#ff0000' }, fill: { openVal: '#ff0000', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect1sMuXufr2Gk',
+      x: -133.5,
+      y: -63,
+      client: { x: -133.5, y: -69 },
+      scale_x: 0.7082353259023925,
+      scale_y: 0.7259259095159254,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -155, y: -104 },
+        tc: { x: -133.5, y: -104 },
+        tr: { x: -112, y: -104 },
+        l: { x: -155, y: -69 },
+        r: { x: -112, y: -69 },
+        bl: { x: -155, y: -34 },
+        bc: { x: -133.5, y: -34 },
+        br: { x: -112, y: -34 },
+      },
+      name: 'rect1',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#ff0000', closeVal: '#ff0000' }, fill: { openVal: '#ff0000', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-linevfbRmEjOka',
+      x: -689.5,
+      y: -28,
+      client: { x: 452, y: 336 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -690, y: -57.5 },
+        tc: { x: -689.5, y: -57.5 },
+        tr: { x: -689, y: -57.5 },
+        l: { x: -690, y: -28 },
+        r: { x: -689, y: -28 },
+        bl: { x: -690, y: 1.5 },
+        bc: { x: -689.5, y: 1.5 },
+        br: { x: -689, y: 1.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 49, y: 109 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect1u3AJvpzHYv' }, end: null },
+    },
+    {
+      id: 'connection_line8SKNmdI7NY',
+      x: -133.5,
+      y: -27,
+      client: { x: -133.5, y: -27 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -134, y: -56.5 },
+        tc: { x: -133.5, y: -56.5 },
+        tr: { x: -133, y: -56.5 },
+        l: { x: -134, y: -27 },
+        r: { x: -133, y: -27 },
+        bl: { x: -134, y: 2.5 },
+        bc: { x: -133.5, y: 2.5 },
+        br: { x: -133, y: 2.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 49, y: 109 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'rect1u3AJvpzHYv' }, end: null },
+    },
+    {
+      id: 'electric-transformerRBBJGgk12b',
+      x: -687,
+      y: 81,
+      client: { x: -687, y: 81 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 1, y: 1, width: 88, height: 160 },
+      point_coordinate: {
+        tl: { x: -731, y: 1 },
+        tc: { x: -687, y: 1 },
+        tr: { x: -643, y: 1 },
+        l: { x: -731, y: 81 },
+        r: { x: -643, y: 81 },
+        bl: { x: -731, y: 161 },
+        bc: { x: -687, y: 161 },
+        br: { x: -643, y: 161 },
+      },
+      name: 'electric-transformer',
+      title: '变压器',
+      tag: 'electric-transformer',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { isOpen: { title: '开关', type: 'Switch', val: false } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'electric-transformerWFdpgdmG1o',
+      x: -129,
+      y: 80,
+      client: { x: -129, y: 80 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 1, y: 1, width: 88, height: 160 },
+      point_coordinate: {
+        tl: { x: -173, y: 0 },
+        tc: { x: -129, y: 0 },
+        tr: { x: -85, y: 0 },
+        l: { x: -173, y: 80 },
+        r: { x: -85, y: 80 },
+        bl: { x: -173, y: 160 },
+        bc: { x: -129, y: 160 },
+        br: { x: -85, y: 160 },
+      },
+      name: 'electric-transformer',
+      title: '变压器-copy',
+      tag: 'electric-transformer',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: { isOpen: { title: '开关', type: 'Switch', val: false } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineQunQ4hosc2',
+      x: -692,
+      y: 193,
+      client: { x: -692, y: 193 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -692, y: 114.5 },
+        tc: { x: -692, y: 114.5 },
+        tr: { x: -692, y: 114.5 },
+        l: { x: -692, y: 193 },
+        r: { x: -692, y: 193 },
+        bl: { x: -692, y: 271.5 },
+        bc: { x: -692, y: 271.5 },
+        br: { x: -692, y: 271.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 50, y: 207 },
+            { x: 50, y: 207 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'electric-transformerRBBJGgk12b' }, end: null },
+    },
+    {
+      id: 'connection_lineVp68SNcEFL',
+      x: -132,
+      y: 192,
+      client: { x: -134, y: 193 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -134, y: 114.5 },
+        tc: { x: -134, y: 114.5 },
+        tr: { x: -134, y: 114.5 },
+        l: { x: -134, y: 193 },
+        r: { x: -134, y: 193 },
+        bl: { x: -134, y: 271.5 },
+        bc: { x: -134, y: 271.5 },
+        br: { x: -134, y: 271.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 50, y: 207 },
+            { x: 50, y: 207 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'electric-transformerRBBJGgk12b' }, end: null },
+    },
+    {
+      id: 'rect2b2ua906HAT',
+      x: -695,
+      y: 266.5,
+      client: { x: -695, y: 266.5 },
+      scale_x: 0.677647070988322,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -727, y: 263 },
+        tc: { x: -695, y: 263 },
+        tr: { x: -663, y: 263 },
+        l: { x: -727, y: 266.5 },
+        r: { x: -663, y: 266.5 },
+        bl: { x: -727, y: 270 },
+        bc: { x: -695, y: 270 },
+        br: { x: -663, y: 270 },
+      },
+      name: 'rect2',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect2iNmTsLMCnq',
+      x: -132,
+      y: 268.5,
+      client: { x: -132, y: 268.5 },
+      scale_x: 0.677647070988322,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -164, y: 265 },
+        tc: { x: -132, y: 265 },
+        tr: { x: -100, y: 265 },
+        l: { x: -164, y: 268.5 },
+        r: { x: -100, y: 268.5 },
+        bl: { x: -164, y: 272 },
+        bc: { x: -132, y: 272 },
+        br: { x: -100, y: 272 },
+      },
+      name: 'rect2',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rectiQQbMJHYM9',
+      x: -692.5,
+      y: 388.5,
+      client: { x: -692.5, y: 388.5 },
+      scale_x: 0.7411765038513409,
+      scale_y: 0.7777777601956344,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -715, y: 351 },
+        tc: { x: -692.5, y: 351 },
+        tr: { x: -670, y: 351 },
+        l: { x: -715, y: 388.5 },
+        r: { x: -670, y: 388.5 },
+        bl: { x: -715, y: 426 },
+        bc: { x: -692.5, y: 426 },
+        br: { x: -670, y: 426 },
+      },
+      name: 'rect',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rectjl8XE7uvYW',
+      x: -132.5,
+      y: 387.5,
+      client: { x: -132.5, y: 382.5 },
+      scale_x: 0.7411765038513409,
+      scale_y: 0.7777777601956344,
+      rotate: 0,
+      actual_bound: { x: 19.64285659790039, y: 1.7857142686843872, width: 60.71428298950195, height: 96.42857360839844 },
+      point_coordinate: {
+        tl: { x: -155, y: 345 },
+        tc: { x: -132.5, y: 345 },
+        tr: { x: -110, y: 345 },
+        l: { x: -155, y: 382.5 },
+        r: { x: -110, y: 382.5 },
+        bl: { x: -155, y: 420 },
+        bc: { x: -132.5, y: 420 },
+        br: { x: -110, y: 420 },
+      },
+      name: 'rect',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-linetgtW9T3tlM',
+      x: -693,
+      y: 477,
+      client: { x: -693, y: 477 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -702.1135158538818, y: 429.05868911743164 },
+        tc: { x: -693, y: 429.05868911743164 },
+        tr: { x: -683.8864841461182, y: 429.05868911743164 },
+        l: { x: -702.1135158538818, y: 477 },
+        r: { x: -683.8864841461182, y: 477 },
+        bl: { x: -702.1135158538818, y: 524.9413108825684 },
+        bc: { x: -693, y: 524.9413108825684 },
+        br: { x: -683.8864841461182, y: 524.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-lineB8uDtRCKgx',
+      x: -133,
+      y: 477,
+      client: { x: -134, y: 476 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -143.11351585388184, y: 428.05868911743164 },
+        tc: { x: -134, y: 428.05868911743164 },
+        tr: { x: -124.88648414611816, y: 428.05868911743164 },
+        l: { x: -143.11351585388184, y: 476 },
+        r: { x: -124.88648414611816, y: 476 },
+        bl: { x: -143.11351585388184, y: 523.9413108825684 },
+        bc: { x: -134, y: 523.9413108825684 },
+        br: { x: -124.88648414611816, y: 523.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-linewAYhKBlISA',
+      x: -693,
+      y: 524.9413108825684,
+      client: { x: 450, y: 889 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -742, y: 393.94131088256836 },
+        tc: { x: -693, y: 393.94131088256836 },
+        tr: { x: -644, y: 393.94131088256836 },
+        l: { x: -742, y: 524.9413108825684 },
+        r: { x: -644, y: 524.9413108825684 },
+        bl: { x: -742, y: 655.9413108825684 },
+        bc: { x: -693, y: 655.9413108825684 },
+        br: { x: -644, y: 655.9413108825684 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 134, y: 50 },
+            { x: 135, y: -205 },
+            { x: 140, y: -209 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'arrow-linetgtW9T3tlM' }, end: null },
+    },
+    {
+      id: 'connection_linezKEzYcoJeW',
+      x: -335,
+      y: 524.9413108825684,
+      client: { x: -335, y: 524.9413108825684 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -388, y: 393.94131088256836 },
+        tc: { x: -335, y: 393.94131088256836 },
+        tr: { x: -282, y: 393.94131088256836 },
+        l: { x: -388, y: 524.9413108825684 },
+        r: { x: -282, y: 524.9413108825684 },
+        bl: { x: -388, y: 655.9413108825684 },
+        bc: { x: -335, y: 655.9413108825684 },
+        br: { x: -282, y: 655.9413108825684 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 253, y: 50 },
+            { x: 172, y: 51 },
+            { x: 173, y: -208 },
+            { x: 173, y: -208 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'BottomCenter', target_id: 'arrow-linetgtW9T3tlM' }, end: null },
+    },
+    {
+      id: 'rect20w5PJBsB2x',
+      x: -539.5,
+      y: 268.5,
+      client: { x: -539.5, y: 268.5 },
+      scale_x: 1.810588267796923,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -625, y: 265 },
+        tc: { x: -539.5, y: 265 },
+        tr: { x: -454, y: 265 },
+        l: { x: -625, y: 268.5 },
+        r: { x: -454, y: 268.5 },
+        bl: { x: -625, y: 272 },
+        bc: { x: -539.5, y: 272 },
+        br: { x: -454, y: 272 },
+      },
+      name: 'rect2',
+      title: '矩形',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'rect2RxYeI9K6JU',
+      x: -272.5,
+      y: 267.5,
+      client: { x: -272.5, y: 267.5 },
+      scale_x: 1.810588267796923,
+      scale_y: 0.5039999846191411,
+      rotate: 0,
+      actual_bound: { x: 2.777777671813965, y: 41.66666793823242, width: 94.44444274902344, height: 13.88888931274414 },
+      point_coordinate: {
+        tl: { x: -358, y: 264 },
+        tc: { x: -272.5, y: 264 },
+        tr: { x: -187, y: 264 },
+        l: { x: -358, y: 267.5 },
+        r: { x: -187, y: 267.5 },
+        bl: { x: -358, y: 271 },
+        bc: { x: -272.5, y: 271 },
+        br: { x: -187, y: 271 },
+      },
+      name: 'rect2',
+      title: '矩形-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {},
+      state: { OnOff: { title: '开关', default: false, props: { fill: { openVal: '#ff0000', closeVal: '#ffff00' } } } },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text662jqUKDwd',
+      x: -102,
+      y: -64,
+      client: { x: -102, y: -64 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -117.5, y: -74 },
+        tc: { x: -102, y: -74 },
+        tr: { x: -86.5, y: -74 },
+        l: { x: -117.5, y: -64 },
+        r: { x: -86.5, y: -64 },
+        bl: { x: -117.5, y: -54 },
+        bc: { x: -102, y: -54 },
+        br: { x: -86.5, y: -54 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '主风机移变' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineqQLg7eRl0i',
+      x: -502,
+      y: 295,
+      client: { x: -485, y: 314 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -512, y: 314 },
+        tc: { x: -485, y: 314 },
+        tr: { x: -458, y: 314 },
+        l: { x: -512, y: 314 },
+        r: { x: -458, y: 314 },
+        bl: { x: -512, y: 314 },
+        bc: { x: -485, y: 314 },
+        br: { x: -458, y: 314 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 51, y: 50 },
+            { x: 97, y: 50 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_linek2NgvxH4Nd',
+      x: -554,
+      y: 294,
+      client: { x: -538, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -565, y: 313 },
+        tc: { x: -538, y: 313 },
+        tr: { x: -511, y: 313 },
+        l: { x: -565, y: 313 },
+        r: { x: -511, y: 313 },
+        bl: { x: -565, y: 313 },
+        bc: { x: -538, y: 313 },
+        br: { x: -511, y: 313 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 59, y: 51 },
+            { x: 103, y: 51 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_lineZu9slDCUUd',
+      x: -321,
+      y: 293,
+      client: { x: -321, y: 314 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -343.5, y: 314 },
+        tc: { x: -321, y: 314 },
+        tr: { x: -298.5, y: 314 },
+        l: { x: -343.5, y: 314 },
+        r: { x: -298.5, y: 314 },
+        bl: { x: -343.5, y: 314 },
+        bc: { x: -321, y: 314 },
+        br: { x: -298.5, y: 314 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 50 },
+            { x: 95, y: 50 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_linelZOGc5aG2N',
+      x: -375,
+      y: 292,
+      client: { x: -399, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -426, y: 313 },
+        tc: { x: -399, y: 313 },
+        tr: { x: -372, y: 313 },
+        l: { x: -426, y: 313 },
+        r: { x: -372, y: 313 },
+        bl: { x: -426, y: 313 },
+        bc: { x: -399, y: 313 },
+        br: { x: -372, y: 313 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 61, y: 51 },
+            { x: 103, y: 51 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_linePOFwnnzvAq',
+      x: -546,
+      y: 343,
+      client: { x: -546, y: 365 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -546.5, y: 342.5 },
+        tc: { x: -546, y: 342.5 },
+        tr: { x: -545.5, y: 342.5 },
+        l: { x: -546.5, y: 365 },
+        r: { x: -545.5, y: 365 },
+        bl: { x: -546.5, y: 387.5 },
+        bc: { x: -546, y: 387.5 },
+        br: { x: -545.5, y: 387.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 51, y: 32 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'electric-breakerfztlV6HGOI',
+      x: -568,
+      y: 375,
+      client: { x: -568, y: 393 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -590.0588989257812, y: 343.82001876831055 },
+        tc: { x: -568, y: 343.82001876831055 },
+        tr: { x: -545.9411010742188, y: 343.82001876831055 },
+        l: { x: -590.0588989257812, y: 393 },
+        r: { x: -545.9411010742188, y: 393 },
+        bl: { x: -590.0588989257812, y: 442.17998123168945 },
+        bc: { x: -568, y: 442.17998123168945 },
+        br: { x: -545.9411010742188, y: 442.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'connection_line26MoSsACzZ',
+      x: -456,
+      y: 343,
+      client: { x: -456, y: 365 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -456.5, y: 342.5 },
+        tc: { x: -456, y: 342.5 },
+        tr: { x: -455.5, y: 342.5 },
+        l: { x: -456.5, y: 365 },
+        r: { x: -455.5, y: 365 },
+        bl: { x: -456.5, y: 387.5 },
+        bc: { x: -456, y: 387.5 },
+        br: { x: -455.5, y: 387.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 33 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'electric-breakeraE7ngUn8TD',
+      x: -478,
+      y: 374,
+      client: { x: -478, y: 391 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -500.05889892578125, y: 341.82001876831055 },
+        tc: { x: -478, y: 341.82001876831055 },
+        tr: { x: -455.94110107421875, y: 341.82001876831055 },
+        l: { x: -500.05889892578125, y: 391 },
+        r: { x: -455.94110107421875, y: 391 },
+        bl: { x: -500.05889892578125, y: 440.17998123168945 },
+        bc: { x: -478, y: 440.17998123168945 },
+        br: { x: -455.94110107421875, y: 440.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器-copy',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'connection_lineibxBHM0S9F',
+      x: -364,
+      y: 339,
+      client: { x: -367, y: 363 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -367.5, y: 340.5 },
+        tc: { x: -367, y: 340.5 },
+        tr: { x: -366.5, y: 340.5 },
+        l: { x: -367.5, y: 363 },
+        r: { x: -366.5, y: 363 },
+        bl: { x: -367.5, y: 385.5 },
+        bc: { x: -367, y: 385.5 },
+        br: { x: -366.5, y: 385.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 36 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'connection_lineJUvw4pt6ft',
+      x: -277,
+      y: 339,
+      client: { x: -277, y: 360 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -277.5, y: 337.5 },
+        tc: { x: -277, y: 337.5 },
+        tr: { x: -276.5, y: 337.5 },
+        l: { x: -277.5, y: 360 },
+        r: { x: -276.5, y: 360 },
+        bl: { x: -277.5, y: 382.5 },
+        bc: { x: -277, y: 382.5 },
+        br: { x: -276.5, y: 382.5 },
+      },
+      name: 'connection_line',
+      title: 'changeLine',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#FFFF00' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: {
+          title: '点坐标',
+          type: 'JsonEdit',
+          val: [
+            { x: 50, y: 37 },
+            { x: 51, y: 2 },
+          ],
+        },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text662jqUKDwd' }, end: null },
+    },
+    {
+      id: 'electric-breakerO6pjkUkcp7',
+      x: -386,
+      y: 376,
+      client: { x: -386, y: 392 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -408.05889892578125, y: 342.82001876831055 },
+        tc: { x: -386, y: 342.82001876831055 },
+        tr: { x: -363.94110107421875, y: 342.82001876831055 },
+        l: { x: -408.05889892578125, y: 392 },
+        r: { x: -363.94110107421875, y: 392 },
+        bl: { x: -408.05889892578125, y: 441.17998123168945 },
+        bc: { x: -386, y: 441.17998123168945 },
+        br: { x: -363.94110107421875, y: 441.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器-copy-copy',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'electric-breakerzbNanrnQvI',
+      x: -301,
+      y: 375,
+      client: { x: -301, y: 375 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 28.222497940063477, y: 0.8181726336479187, width: 44.1177978515625, height: 98.3599624633789 },
+      point_coordinate: {
+        tl: { x: -323.05889892578125, y: 325.82001876831055 },
+        tc: { x: -301, y: 325.82001876831055 },
+        tr: { x: -278.94110107421875, y: 325.82001876831055 },
+        l: { x: -323.05889892578125, y: 375 },
+        r: { x: -278.94110107421875, y: 375 },
+        bl: { x: -323.05889892578125, y: 424.17998123168945 },
+        bc: { x: -301, y: 424.17998123168945 },
+        br: { x: -278.94110107421875, y: 424.17998123168945 },
+      },
+      name: 'electric-breaker',
+      title: '电源断路器-copy-copy-copy',
+      tag: 'electric-breaker',
+      type: 'CustomSvg',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      props: {
+        stroke: { title: '边框色', type: 'Color', val: '#00ff00' },
+        fill: { title: '填充色', type: 'Color', val: '#00ff00' },
+        isOpen: { title: '开关', type: 'Switch', val: false },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-line5bLLa1fo6m',
+      x: -547,
+      y: 471,
+      client: { x: -547, y: 488 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -556.1135158538818, y: 440.05868911743164 },
+        tc: { x: -547, y: 440.05868911743164 },
+        tr: { x: -537.8864841461182, y: 440.05868911743164 },
+        l: { x: -556.1135158538818, y: 488 },
+        r: { x: -537.8864841461182, y: 488 },
+        bl: { x: -556.1135158538818, y: 535.9413108825684 },
+        bc: { x: -547, y: 535.9413108825684 },
+        br: { x: -537.8864841461182, y: 535.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-lineqPB3ix7BkL',
+      x: -457,
+      y: 472,
+      client: { x: -457, y: 472 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -466.11351585388184, y: 424.05868911743164 },
+        tc: { x: -457, y: 424.05868911743164 },
+        tr: { x: -447.88648414611816, y: 424.05868911743164 },
+        l: { x: -466.11351585388184, y: 472 },
+        r: { x: -447.88648414611816, y: 472 },
+        bl: { x: -466.11351585388184, y: 519.9413108825684 },
+        bc: { x: -457, y: 519.9413108825684 },
+        br: { x: -447.88648414611816, y: 519.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-lineBoydWOHHmr',
+      x: -366,
+      y: 471,
+      client: { x: -366, y: 471 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -375.11351585388184, y: 423.05868911743164 },
+        tc: { x: -366, y: 423.05868911743164 },
+        tr: { x: -356.88648414611816, y: 423.05868911743164 },
+        l: { x: -375.11351585388184, y: 471 },
+        r: { x: -356.88648414611816, y: 471 },
+        bl: { x: -375.11351585388184, y: 518.9413108825684 },
+        bc: { x: -366, y: 518.9413108825684 },
+        br: { x: -356.88648414611816, y: 518.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'arrow-line5waKsA7PHF',
+      x: -280,
+      y: 473,
+      client: { x: -282, y: 473 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 40.88562774658203, y: -0.0006357083912007511, width: 18.227031707763672, height: 95.88262176513672 },
+      point_coordinate: {
+        tl: { x: -291.11351585388184, y: 425.05868911743164 },
+        tc: { x: -282, y: 425.05868911743164 },
+        tr: { x: -272.88648414611816, y: 425.05868911743164 },
+        l: { x: -291.11351585388184, y: 473 },
+        r: { x: -272.88648414611816, y: 473 },
+        bl: { x: -291.11351585388184, y: 520.9413108825684 },
+        bc: { x: -282, y: 520.9413108825684 },
+        br: { x: -272.88648414611816, y: 520.9413108825684 },
+      },
+      name: 'arrow-line',
+      title: '箭头1-copy-copy-copy',
+      type: 'File',
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      display: true,
+      state: {
+        OnOff: {
+          title: '开关',
+          default: false,
+          props: { stroke: { openVal: '#00ff00', closeVal: '#ffff00' }, fill: { openVal: '#00ff00', closeVal: '#ff000000' } },
+        },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text9mE6DlRsxq',
+      x: -662,
+      y: -63,
+      client: { x: -662, y: -63 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -700, y: -73 },
+        tc: { x: -662, y: -73 },
+        tr: { x: -624, y: -73 },
+        l: { x: -700, y: -63 },
+        r: { x: -624, y: -63 },
+        bl: { x: -700, y: -53 },
+        bc: { x: -662, y: -53 },
+        br: { x: -624, y: -53 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '备风机移变' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textffQAK2KK7l',
+      x: -512,
+      y: 313,
+      client: { x: -512, y: 313 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -524.4000005722046, y: 297 },
+        tc: { x: -512, y: 297 },
+        tr: { x: -499.5999994277954, y: 297 },
+        l: { x: -524.4000005722046, y: 313 },
+        r: { x: -499.5999994277954, y: 313 },
+        bl: { x: -524.4000005722046, y: 329 },
+        bc: { x: -512, y: 329 },
+        br: { x: -499.5999994277954, y: 329 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '备' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 24 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00DDFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textErE3B1l7S1',
+      x: -334,
+      y: 312,
+      client: { x: -334, y: 312 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -346.4000005722046, y: 296 },
+        tc: { x: -334, y: 296 },
+        tr: { x: -321.5999994277954, y: 296 },
+        l: { x: -346.4000005722046, y: 312 },
+        r: { x: -321.5999994277954, y: 312 },
+        bl: { x: -346.4000005722046, y: 328 },
+        bc: { x: -334, y: 328 },
+        br: { x: -321.5999994277954, y: 328 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '主' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 24 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00DDFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textIjsFbs6fID',
+      x: -675,
+      y: -172,
+      client: { x: -675, y: -172 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -782.466552734375, y: -182 },
+        tc: { x: -675, y: -182 },
+        tr: { x: -567.533447265625, y: -182 },
+        l: { x: -782.466552734375, y: -172 },
+        r: { x: -567.533447265625, y: -172 },
+        bl: { x: -782.466552734375, y: -162 },
+        bc: { x: -675, y: -162 },
+        br: { x: -567.533447265625, y: -162 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '来在12煤三盘区变电所G1211柜' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textWilG5jRH7w',
+      x: -353,
+      y: -172,
+      client: { x: -353, y: -172 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -460.466552734375, y: -182 },
+        tc: { x: -353, y: -182 },
+        tr: { x: -245.533447265625, y: -182 },
+        l: { x: -460.466552734375, y: -172 },
+        r: { x: -245.533447265625, y: -172 },
+        bl: { x: -460.466552734375, y: -162 },
+        bc: { x: -353, y: -162 },
+        br: { x: -245.533447265625, y: -162 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '来在12煤三盘区变电所G1107柜' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textcxjU8wN810',
+      x: -137,
+      y: 553,
+      client: { x: -137, y: 553 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -152.5, y: 543 },
+        tc: { x: -137, y: 543 },
+        tr: { x: -121.5, y: 543 },
+        l: { x: -152.5, y: 553 },
+        r: { x: -121.5, y: 553 },
+        bl: { x: -152.5, y: 563 },
+        bc: { x: -137, y: 563 },
+        br: { x: -121.5, y: 563 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '主风机馈电' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textHXkhPmUMWE',
+      x: -742,
+      y: 551,
+      client: { x: -742, y: 551 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -779.6000022888184, y: 541 },
+        tc: { x: -742, y: 541 },
+        tr: { x: -704.3999977111816, y: 541 },
+        l: { x: -779.6000022888184, y: 551 },
+        r: { x: -704.3999977111816, y: 551 },
+        bl: { x: -779.6000022888184, y: 561 },
+        bc: { x: -742, y: 561 },
+        br: { x: -704.3999977111816, y: 561 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '备风机馈电' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFFFFF' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textH6apeUpS25',
+      x: -280,
+      y: -100,
+      client: { x: -280, y: -100 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -325.5, y: -110 },
+        tc: { x: -280, y: -110 },
+        tr: { x: -234.5, y: -110 },
+        l: { x: -325.5, y: -100 },
+        r: { x: -234.5, y: -100 },
+        bl: { x: -325.5, y: -90 },
+        bc: { x: -280, y: -90 },
+        br: { x: -234.5, y: -90 },
+      },
+      name: 'custom-svg-text',
+      title: '文字',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '高压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textdlSMN5CrsK',
+      x: -281,
+      y: 127,
+      client: { x: -281, y: 127 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -326.5, y: 117 },
+        tc: { x: -281, y: 117 },
+        tr: { x: -235.5, y: 117 },
+        l: { x: -326.5, y: 127 },
+        r: { x: -235.5, y: 127 },
+        bl: { x: -326.5, y: 137 },
+        bc: { x: -281, y: 137 },
+        br: { x: -235.5, y: 137 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '低压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text8hfqYu7qCf',
+      x: -838,
+      y: 127,
+      client: { x: -838, y: 127 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -883.5, y: 117 },
+        tc: { x: -838, y: 117 },
+        tr: { x: -792.5, y: 117 },
+        l: { x: -883.5, y: 127 },
+        r: { x: -792.5, y: 127 },
+        bl: { x: -883.5, y: 137 },
+        bc: { x: -838, y: 137 },
+        br: { x: -792.5, y: 137 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '低压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textYN6br3c8mY',
+      x: -835,
+      y: -100,
+      client: { x: -835, y: -105 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -880.5, y: -115 },
+        tc: { x: -835, y: -115 },
+        tr: { x: -789.5, y: -115 },
+        l: { x: -880.5, y: -105 },
+        r: { x: -789.5, y: -105 },
+        bl: { x: -880.5, y: -95 },
+        bc: { x: -835, y: -95 },
+        br: { x: -789.5, y: -95 },
+      },
+      name: 'custom-svg-text',
+      title: '文字-copy-copy-copy',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '高压运行状态' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#FFA600' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-text9OtB4BD8tx',
+      x: -811,
+      y: -75,
+      client: { x: -811, y: -78 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -826.1000003814697, y: -88 },
+        tc: { x: -811, y: -88 },
+        tr: { x: -795.8999996185303, y: -88 },
+        l: { x: -826.1000003814697, y: -78 },
+        r: { x: -795.8999996185303, y: -78 },
+        bl: { x: -826.1000003814697, y: -68 },
+        bc: { x: -811, y: -68 },
+        br: { x: -795.8999996185303, y: -68 },
+      },
+      name: 'custom-svg-text',
+      title: 'b-state',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textifb0BW0nZX',
+      x: -252,
+      y: -74,
+      client: { x: -252, y: -74 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -267.1000003814697, y: -84 },
+        tc: { x: -252, y: -84 },
+        tr: { x: -236.89999961853027, y: -84 },
+        l: { x: -267.1000003814697, y: -74 },
+        r: { x: -236.89999961853027, y: -74 },
+        bl: { x: -267.1000003814697, y: -64 },
+        bc: { x: -252, y: -64 },
+        br: { x: -236.89999961853027, y: -64 },
+      },
+      name: 'custom-svg-text',
+      title: 'z-state',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'straight-lineFGURWExYla',
+      x: -811,
+      y: -88,
+      client: { x: 347, y: 258 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 50, y: 50, width: 0, height: 0 },
+      point_coordinate: {
+        tl: { x: -811, y: -88 },
+        tc: { x: -811, y: -88 },
+        tr: { x: -811, y: -88 },
+        l: { x: -811, y: -88 },
+        r: { x: -811, y: -88 },
+        bl: { x: -811, y: -88 },
+        bc: { x: -811, y: -88 },
+        br: { x: -811, y: -88 },
+      },
+      name: 'connection_line',
+      title: '连接线',
+      type: 'ConnectionLine',
+      config: { can_zoom: false, have_anchor: false, actual_rect: false },
+      display: true,
+      props: {
+        stroke: { title: '线条颜色', type: 'Color', val: '#ff0000' },
+        'stroke-width': { title: '线条宽度', type: 'InputNumber', val: 2 },
+        point_position: { title: '点坐标', type: 'JsonEdit', val: [{ x: 50, y: 50 }] },
+      },
+      animations: {
+        type: {
+          title: '动画类型',
+          type: 'Select',
+          val: 'None',
+          options: [
+            { label: '无', value: 'None' },
+            { label: '电流', value: 'Electricity' },
+            { label: '轨迹', value: 'Track' },
+            { label: '水珠', value: 'WaterDrop' },
+          ],
+        },
+        dur: { title: '持续时间', type: 'InputNumber', val: 20 },
+        repeatCount: { title: '循环次数', type: 'Input', val: 'indefinite', disabled: true },
+        color: { title: '颜色', type: 'Color', val: '#0a7ae2' },
+        reverse: { title: '反转动画', type: 'Switch', val: false },
+      },
+      bind_anchors: { start: { type: 'TopCenter', target_id: 'custom-svg-text9OtB4BD8tx' }, end: null },
+    },
+    {
+      id: 'custom-svg-textlqc2YZTzyI',
+      x: -815,
+      y: 153,
+      client: { x: -815, y: 153 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -830.1000003814697, y: 143 },
+        tc: { x: -815, y: 143 },
+        tr: { x: -799.8999996185303, y: 143 },
+        l: { x: -830.1000003814697, y: 153 },
+        r: { x: -799.8999996185303, y: 153 },
+        bl: { x: -830.1000003814697, y: 163 },
+        bc: { x: -815, y: 163 },
+        br: { x: -799.8999996185303, y: 163 },
+      },
+      name: 'custom-svg-text',
+      title: 'b-state1',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+    {
+      id: 'custom-svg-textwo1kl0CsXG',
+      x: -249,
+      y: 151,
+      client: { x: -249, y: 151 },
+      scale_x: 1,
+      scale_y: 1,
+      rotate: 0,
+      actual_bound: { x: 49.20000076293945, y: 39, width: 31, height: 20 },
+      point_coordinate: {
+        tl: { x: -264.1000003814697, y: 141 },
+        tc: { x: -249, y: 141 },
+        tr: { x: -233.89999961853027, y: 141 },
+        l: { x: -264.1000003814697, y: 151 },
+        r: { x: -233.89999961853027, y: 151 },
+        bl: { x: -264.1000003814697, y: 161 },
+        bc: { x: -249, y: 161 },
+        br: { x: -233.89999961853027, y: 161 },
+      },
+      name: 'custom-svg-text',
+      title: 'z-state1',
+      tag: 'custom-svg-text',
+      type: 'CustomSvg',
+      display: true,
+      config: { can_zoom: true, have_anchor: true, actual_rect: true },
+      props: {
+        text: { title: '文字内容', type: 'Input', val: '正常' },
+        fontFamily: {
+          title: '字体',
+          type: 'Select',
+          val: 'Microsoft YaHei',
+          options: [
+            { value: 'Microsoft YaHei', label: '微软雅黑' },
+            { value: 'NSimSun', label: '新宋体' },
+          ],
+        },
+        fontSize: { title: '文字大小', type: 'InputNumber', val: 15 },
+        fill: { title: '文字颜色', type: 'Color', val: '#00FF00' },
+      },
+      common_animations: { val: '', delay: 'delay-0s', speed: 'slow', repeat: 'infinite' },
+    },
+  ],
+});
+
+export const option = reactive<EChartsOption>({
+  title: {
+    text: '局部通风机运行工况智能决策',
+    textStyle: {
+      color: '#BF954D',
+    },
+    left: 'center',
+    top: 0,
+  },
+  // backgroundColor: '#39deff',
+  tooltip: {
+    trigger: 'axis',
+    axisPointer: {
+      type: 'cross',
+      label: {
+        backgroundColor: '#6a7985',
+      },
+    },
+  },
+  toolbox: {
+    show: true,
+  },
+  grid: {
+    left: 8,
+    right: 50,
+    bottom: 0,
+    containLabel: true,
+  },
+  xAxis: {
+    type: 'category',
+    name: 'm³/min',
+    nameTextStyle: {
+      fontWeight: 600,
+      fontSize: 13,
+    },
+    splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+    axisLabel: {
+      margin: 10,
+      fontSize: 14,
+      color: '#f1f1f199',
+    },
+    boundaryGap: false,
+    data: [],
+  },
+  yAxis: {
+    type: 'value',
+    axisLine: {
+      show: true,
+      lineStyle: {
+        color: '#006c9d',
+      },
+    },
+    splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+    axisLabel: {
+      show: true,
+      fontSize: 14,
+      formatter: '{value}',
+      color: '#0071A5',
+    },
+    min: 360,
+    max: 9000,
+    name: 'Pa',
+    nameTextStyle: {
+      fontWeight: 600,
+      fontSize: 13,
+    },
+  },
+  series: [],
+});
+export const echatsOption = {
+  // tooltip: {
+  //   show: true,
+  //   formatter: function (datas: []) {
+  //     return datas.map((item) => {
+  //       item['data'] = item['data'].toFixed(2);
+  //       return item;
+  //     });
+  //   },
+  // },
+  legend: {
+    top: -10,
+  },
+  grid: {
+    top: '15%',
+    left: '20',
+    right: '25',
+    bottom: '0',
+    containLabel: true,
+  },
+  toolbox: {
+    feature: {
+      saveAsImage: {
+        show: false,
+      },
+    },
+  },
+  xAxis: {
+    type: 'category',
+    axisLabel: {
+      margin: 10,
+      color: '#f1f1f199',
+    },
+    name: 'm³/min',
+  },
+  yAxis: {
+    axisLabel: {
+      color: '#0071A5',
+    },
+  },
+};
+
+export const chartsColumnList = [
+  {
+    legend: '瓦斯浓度',
+    seriesName: '(%)',
+    ymax: 0.8,
+    yname: '%',
+    linetype: 'line',
+    yaxispos: 'left',
+    color: '#00FFA8',
+    sort: 1,
+    xRotate: 0,
+    dataIndex: 'gas',
+  },
+  {
+    legend: '风量',
+    seriesName: '(m³/min)',
+    ymax: 1100,
+    yname: 'm³/min',
+    linetype: 'line',
+    yaxispos: 'right',
+    color: '#FDB146',
+    sort: 2,
+    xRotate: 0,
+    dataIndex: 'm3',
+  },
+  {
+    legend: '频率',
+    seriesName: '(Hz)',
+    ymax: 50,
+    yname: 'Hz',
+    linetype: 'line',
+    yaxispos: 'right',
+    color: '#AE19FF',
+    sort: 3,
+    xRotate: 0,
+    dataIndex: 'Hz',
+  },
+];
+
+export const initData = () => {
+  const num = 3;
+  const obj = {
+    angle: 0,
+    Hz: 35.0,
+    a: -0.0626027929595192,
+    b: 44.737585902203136,
+    c: -4047.5601190339376,
+    min: 300,
+    max: 1100.0,
+  };
+  const a = -0.0626,
+    m = 44.737589,
+    n = -4047.56012;
+
+  const maxList = [519, 587, 659.4, 737, 820.7];
+  const minList = [264, 303.7, 346, 387.2, 429.1];
+  const data = [];
+  for (let i = -1; i <= num; i++) {
+    const item = cloneDeep(obj);
+    item['a'] = Math.round((a + 0.003 * i) * 10000) / 10000;
+    item['Hz'] = 35 + i * 5;
+    item['c'] = n + 0.6 * i;
+    item['b'] = m + i * 1.9;
+    item['max'] = maxList[i + 1];
+    item['min'] = minList[i + 1];
+    data.push(item);
+  }
+  return data;
+};
+
+export const fanInfoData = reactive({
+  fj: '一号回风井',
+  xh: 'FBCDZ No.29',
+  gl: '2×500',
+  edgl: '740',
+  eddy: '10000',
+  eddl: '38.4',
+  flfw: '110~260',
+  fyfw: '200~4100',
+  fbdj: 'ExdI',
+  ccrq: '2010.07',
+  sccj: '南阳防爆',
+  tjfs: '变频调节',
+  plfw: '30~50',
+});
+
+export const fanInfo = [
+  {
+    title: '风井',
+    code: 'fj',
+    value: '一号回风井',
+  },
+  {
+    title: '型号',
+    code: 'xh',
+    value: 'FBCDZ No.29',
+  },
+  {
+    title: '功率(kW)',
+    code: 'gl',
+    value: '2×500',
+  },
+  {
+    title: '额定转速(r/min)',
+    code: 'edgl',
+    value: '740',
+  },
+  {
+    title: '额定电压(V)',
+    code: 'eddy',
+    value: '10000',
+  },
+  {
+    title: '额定电流(A)',
+    code: 'eddl',
+    value: '38.4',
+  },
+  {
+    title: '风量范围(m³/s)',
+    code: 'flfw',
+    value: '110~260',
+  },
+  {
+    title: '风压范围(Pa)',
+    code: 'fyfw',
+    value: '200~4100',
+  },
+  {
+    title: '防爆等级',
+    code: 'fbdj',
+    value: 'ExdI',
+  },
+  {
+    title: '出厂日期',
+    code: 'ccrq',
+    value: '2010.07',
+  },
+  {
+    title: '生产厂家',
+    code: 'sccj',
+    value: '南阳防爆',
+  },
+  {
+    title: '调节方式',
+    code: 'tjfs',
+    value: '变频调节',
+  },
+  {
+    title: '频率可调范围(Hz)',
+    code: 'plfw',
+    value: '30~50',
+  },
+];
+
+export const getSchamas = (): FormSchema[] => {
+  return [
+    {
+      field: 'fj',
+      component: 'Input',
+      label: '风井',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'xh',
+      component: 'Input',
+      label: '型号',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'gl',
+      component: 'Input',
+      label: '功率(kW)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'edgl',
+      component: 'Input',
+      label: '额定转速(r/min)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'eddy',
+      component: 'Input',
+      label: '额定电压(V)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'eddl',
+      component: 'Input',
+      label: '额定电流(A)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'flfw',
+      component: 'Input',
+      label: '风量范围(m³/s)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'fyfw',
+      component: 'Input',
+      label: '风压范围(Pa)',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'fbdj',
+      component: 'Select',
+      label: '防爆等级',
+      colProps: {
+        span: 6,
+      },
+      componentProps: {
+        options: [
+          {
+            label: 'ExdI',
+            value: 'ExdI',
+            key: '1',
+          },
+        ],
+      },
+    },
+    {
+      field: 'ccrq',
+      component: 'Input',
+      label: '出厂日期',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'sccj',
+      component: 'Input',
+      label: '生产厂家',
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'tjfs',
+      component: 'Select',
+      label: '调节方式',
+      colProps: {
+        span: 6,
+      },
+      componentProps: {
+        options: [
+          {
+            label: '变频调节',
+            value: '变频调节',
+            key: '1',
+          },
+        ],
+      },
+    },
+    {
+      field: 'plfw',
+      component: 'Input',
+      label: '频率可调范围(Hz)',
+      colProps: {
+        span: 6,
+      },
+    },
+  ];
+};
+
+export const getSchamas1 = (): FormSchema[] => {
+  return [
+    {
+      field: 'Hz',
+      component: 'InputNumber',
+      label: '频率(Hz)',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'a',
+      component: 'InputNumber',
+      label: '二次项系数',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'b',
+      component: 'InputNumber',
+      label: '一次项系数',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'c',
+      component: 'InputNumber',
+      label: '常数项系数',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'min',
+      component: 'InputNumber',
+      label: '风量下限(m³/s)',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+    {
+      field: 'max',
+      component: 'InputNumber',
+      label: '风量上限(m³/s)',
+      required: true,
+      colProps: {
+        span: 6,
+      },
+    },
+  ];
+};
+
+export const lineFormData = reactive({
+  Hz: null,
+  a: null,
+  b: null,
+  c: null,
+  min: null,
+  max: null,
+});

+ 655 - 0
src/views/vent/monitorManager/fanLocalMonitor1/fanLocal.three.ts

@@ -0,0 +1,655 @@
+import * as THREE from 'three';
+import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
+import { animateCamera, getTextCanvas, renderVideo, updateAxisCenter } from '/@/utils/threejs/util';
+import UseThree from '../../../../utils/threejs/useThree';
+import fcFan from './fcfanLocal.three';
+import fmFan from './fmfanLocal.three';
+import Smoke from '/@/views/vent/comment/threejs/Smoke';
+import gsap from 'gsap';
+import useEvent from '../../../../utils/threejs/useEvent';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+const modelName = 'jbfj-hd';
+// 模型对象、 文字对象
+let model: UseThree | undefined,
+  group: THREE.Object3D | undefined,
+  fcFanObj: fcFan | undefined,
+  fmFanObj: fmFan | undefined,
+  player1,
+  fanType,
+  topSmoke: Smoke | undefined,
+  downSmoke: Smoke | undefined, //
+  returnSmoke: Smoke | undefined,
+  topLife: number | undefined,
+  downLife: number | undefined,
+  playerStartClickTime1 = new Date().getTime();
+
+const { mouseDownFn, mousemoveFn, mouseUpFn } = useEvent();
+
+// 打灯光
+const addLight = () => {
+  const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
+  directionalLight.position.set(-564, 602, -261);
+  group?.add(directionalLight);
+  // directionalLight.target = group;
+
+  // const spotLight = new THREE.SpotLight();
+  // spotLight.angle = Math.PI / 16;
+  // spotLight.penumbra = 0;
+  // spotLight.castShadow = true;
+  // spotLight.position.set(0, 463, 687);
+  // scene.add(spotLight);
+
+  // spotLight.shadow.camera.near = 0.5; // default
+  // spotLight.shadow.camera.far = 1000; // default
+  // spotLight.shadow.focus = 1;
+  // spotLight.shadow.bias = -0.000002;
+  // spotLight.target = group;
+
+  // const pointLight6 = new THREE.PointLight(0xffffff, 1, 500);
+  // pointLight6.position.set(-131, 64, -1);
+  // pointLight6.shadow.bias = 0.05;
+  // group?.add(pointLight6);
+
+  // gui.add(directionalLight.position, 'x', -1000, 1000);
+  // gui.add(directionalLight.position, 'y', -1000, 1000);
+  // gui.add(directionalLight.position, 'z', -1000, 1000);
+
+  // gui.add(pointLight6.position, 'x', -500, 500);
+  // gui.add(pointLight6.position, 'y', -500, 500);
+  // gui.add(pointLight6.position, 'z', -500, 500);
+  // gui.add(pointLight6, 'distance', 0, 500);
+};
+
+// 重置摄像头
+const resetCamera = () => {
+  model.camera.position.set(0, -1000, 100);
+  model.camera.far = 1000;
+  model.orbitControls?.update();
+  model.camera.updateProjectionMatrix();
+};
+
+// 设置模型位置
+const setModalPosition = () => {
+  if (!group) return;
+  group.position.set(0, 10, -50);
+  group.rotation.y = Math.PI / 2;
+};
+
+const setControls = () => {
+  if (model && model.orbitControls) {
+    model.orbitControls.panSpeed = 0.5;
+    model.orbitControls.rotateSpeed = 0.5;
+    model.orbitControls.maxPolarAngle = Math.PI / 2.4;
+    model.orbitControls.minPolarAngle = Math.PI / 3;
+  }
+};
+
+// 切换局部通风机类型
+export const setModelType = (type) => {
+  fanType = type;
+  return new Promise((resolve) => {
+    // 显示双道风窗
+    let childGroup;
+    if (fanType === 'fm' && fcFanObj && fcFanObj.group) {
+      if (group?.getObjectByName('jbfj-fc')) {
+        group?.remove(fcFanObj.group);
+      }
+      childGroup = fmFanObj?.group;
+      if (group && group?.getObjectByName('text5') && group?.getObjectByName('text4')) {
+        group.getObjectByName('text5')['visible'] = false;
+        group.getObjectByName('text4')['visible'] = true;
+      }
+    } else if (fanType === 'fc' && fmFanObj && fmFanObj.group) {
+      // 显示单道风窗
+      if (group?.getObjectByName('jbfj-fm')) {
+        group?.remove(fmFanObj.group);
+      }
+      childGroup = fcFanObj?.group;
+      if (group && group?.getObjectByName('text5') && group?.getObjectByName('text4')) {
+        group.getObjectByName('text5')['visible'] = true;
+        group.getObjectByName('text4')['visible'] = false;
+      }
+    } else {
+      if (group?.getObjectByName('jbfj-fc')) {
+        group?.remove(fcFanObj.group);
+      }
+      if (group?.getObjectByName('jbfj-fm')) {
+        group?.remove(fmFanObj.group);
+      }
+      if (group && group?.getObjectByName('text5') && group?.getObjectByName('text4')) {
+        group.getObjectByName('text5')['visible'] = false;
+        group.getObjectByName('text4')['visible'] = false;
+      }
+      childGroup = null;
+    }
+    setTimeout(async () => {
+      if (childGroup) group?.add(childGroup);
+      const oldCameraPosition = { x: 615, y: 275, z: 744 };
+      await animateCamera(oldCameraPosition, { x: 0, y: 0, z: 0 }, { x: 0.08, y: 21.73, z: 78.45 }, { x: 0.13, y: -0.82, z: 0.236 }, model, 0.8);
+      resolve(null);
+    }, 300);
+  });
+};
+
+/* 添加监控数据 */
+export const addText = (selectData) => {
+  if (!group) {
+    return;
+  }
+  const textArr = [
+    {
+      text: `智能局部通风机监测与控制系统`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 20,
+      y: 108,
+    },
+    {
+      text: `供风距离(m):`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 0,
+      y: 152,
+    },
+    {
+      text: `${
+        selectData.fchimenylength ? selectData.fchimenylength : selectData.airSupplyDistence_merge ? selectData.airSupplyDistence_merge : '-'
+      }`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 228,
+      y: 152,
+    },
+    {
+      text: `风筒直径(mm): `,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 0,
+      y: 200,
+    },
+    {
+      text: ` ${selectData.fchimenydiamlimit ? selectData.fchimenydiamlimit : selectData.ductDiameter_merge ? selectData.ductDiameter_merge : '-'}`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 220,
+      y: 200,
+    },
+    {
+      text: `故障诊断:`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 0,
+      y: 245,
+    },
+    {
+      text: `${selectData.warnLevel_str ? selectData.warnLevel_str : '-'}`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 220,
+      y: 245,
+    },
+    {
+      text: `型号功率:`,
+      font: 'normal 30px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 0,
+      y: 285,
+    },
+    {
+      text: `${selectData.model_Power_merge ? selectData.model_Power_merge : '-'}`,
+      font: 'normal 26px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: 220,
+      y: 285,
+    },
+    {
+      text: History_Type['type'] == 'remote' ? `国能神东煤炭集团监制` : '煤炭科学技术研究院有限公司研制',
+      font: 'normal 28px Arial',
+      color: '#009900',
+      strokeStyle: '#002200',
+      x: History_Type['type'] == 'remote' ? 80 : 20, //20  煤炭科学技术研究院有限公司研制
+      y: 325,
+    },
+  ];
+  getTextCanvas(526, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      // 关于材质并未讲解 实操即可熟悉                 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.FrontSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    const monitorPlane = 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.0135, 0.0135, 0.0135);
+      planeMesh.rotation.y = -Math.PI / 2;
+      planeMesh.position.set(-84.79, 0.82, 17.0);
+      group.add(planeMesh);
+    }
+  });
+};
+
+// // css3D文字
+export const addCssText = () => {
+  if (!group) return;
+
+  if (!group.getObjectByName('text1')) {
+    const element = document.getElementById('inputBox') as HTMLElement;
+    if (element) {
+      const fanLocalCSS3D = new CSS3DObject(element);
+      fanLocalCSS3D.name = 'text1';
+      fanLocalCSS3D.scale.set(0.04, 0.04, 0.04);
+      fanLocalCSS3D.rotation.y = -Math.PI / 2;
+      fanLocalCSS3D.position.set(-85.68, 5.97, -3.39);
+      group.add(fanLocalCSS3D);
+    }
+  }
+
+  if (!group.getObjectByName('text2')) {
+    const element = document.getElementById('outBox') as HTMLElement;
+    if (element) {
+      const fanLocalCSS3D = new CSS3DObject(element);
+      fanLocalCSS3D.name = 'text2';
+      fanLocalCSS3D.scale.set(0.1, 0.1, 0.1);
+      fanLocalCSS3D.rotation.y = -Math.PI / 2;
+      fanLocalCSS3D.position.set(74.63, 13.54, 3.84);
+      group.add(fanLocalCSS3D);
+    }
+  }
+  if (!group.getObjectByName('text3')) {
+    const element = document.getElementById('returnBox') as HTMLElement;
+    if (element) {
+      const fanLocalCSS3D = new CSS3DObject(element);
+      fanLocalCSS3D.name = 'text3';
+      fanLocalCSS3D.scale.set(0.07, 0.07, 0.07);
+      fanLocalCSS3D.rotation.y = -Math.PI / 2;
+      fanLocalCSS3D.position.set(-25.97, 9.3, -15.09);
+      group.add(fanLocalCSS3D);
+    }
+  }
+  if (!group.getObjectByName('text4')) {
+    const element = document.getElementById('gateBox') as HTMLElement;
+    if (element) {
+      // element.innerHTML = '';
+      const fanLocalCSS3D = new CSS3DObject(element);
+      fanLocalCSS3D.name = 'text4';
+      fanLocalCSS3D.scale.set(0.04, 0.04, 0.04);
+      fanLocalCSS3D.rotation.y = -Math.PI / 2;
+      fanLocalCSS3D.position.set(-73.13, 8.44, -23.52);
+      group.add(fanLocalCSS3D);
+    }
+  }
+  if (!group.getObjectByName('text5')) {
+    const element = document.getElementById('windownBox') as HTMLElement;
+    if (element) {
+      // element.innerHTML = '';
+      const fanLocalCSS3D = new CSS3DObject(element);
+      fanLocalCSS3D.name = 'text5';
+      fanLocalCSS3D.scale.set(0.07, 0.07, 0.07);
+      fanLocalCSS3D.rotation.y = -Math.PI / 2;
+      fanLocalCSS3D.position.set(-28.44, 9.78, -40.42);
+      group.add(fanLocalCSS3D);
+    }
+  }
+  if (!group.getObjectByName('text6')) {
+    const element = document.getElementById('inputBox1') as HTMLElement;
+    if (element) {
+      const fanLocalCSS3D = new CSS3DObject(element);
+      fanLocalCSS3D.name = 'text6';
+      fanLocalCSS3D.scale.set(0.04, 0.04, 0.04);
+      fanLocalCSS3D.rotation.y = -Math.PI / 2;
+      fanLocalCSS3D.position.set(-84.23, 4.97, -18.92);
+      group.add(fanLocalCSS3D);
+    }
+  }
+};
+
+// export const playSmoke = (controlType, deviceType, frequency, state) => {
+//   if (frequency) {
+//     setSmokeFrequency(deviceType, frequency);
+//   }
+//   if (controlType === 'startSmoke') {
+//     runFly(deviceType, state);
+//   }
+// };
+export const playSmoke = (selectData) => {
+  // debugger;
+  console.log('selectData[Fan1fHz]------------》', selectData['Fan1fHz'], Number(selectData['Fan1fHz']));
+  if (selectData['Fan1StartStatus'] == '1') {
+    // 主风机打开
+    // setSmokeFrequency('top', Number(selectData['Fan1fHz']) || 40);
+    setSmokeFrequency('top', 40);
+    runFly('top', 'open');
+  } else {
+    // 备风机关闭
+    runFly('top', 'close');
+  }
+  if (selectData['Fan2StartStatus'] == '1') {
+    // 备风机打开
+    // setSmokeFrequency('down', Number(selectData['Fan2fHz']) || 40);
+    setSmokeFrequency('down', 40);
+    runFly('down', 'open');
+  } else {
+    // 备风机关闭
+    runFly('down', 'close');
+  }
+
+  if (selectData['Fan1StartStatus'] != '1' && selectData['Fan2StartStatus'] != '1') {
+    runFly('all', 'close');
+  }
+
+  // if (frequency) {
+  //   setSmokeFrequency(deviceType, frequency);
+  // }
+  // if (controlType === 'startSmoke') {
+  //   runFly(deviceType, state);
+  // }
+};
+
+const initFly = async () => {
+  const topCurve = [
+    {
+      path0: new THREE.Vector3(-89.84, 2.359, 4.91),
+      path1: new THREE.Vector3(-85.678, 2.359, 3.61),
+      isSpread: true,
+      spreadDirection: -1, //
+    },
+    {
+      path0: new THREE.Vector3(-85.678, 2.352, 3.66),
+      path1: new THREE.Vector3(-85.636, 2.353, -3.829),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(-85.636, 2.353, -3.829),
+      path1: new THREE.Vector3(-85.636, 1.026, -5.881),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(-85.636, 1.026, -5.881),
+      path1: new THREE.Vector3(-85.618, 0.887, -12.862),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(-85.618, 0.827, -12.962),
+      path1: new THREE.Vector3(80.404, 0.827, -12.962),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(80.404, 0.827, -12.962),
+      path1: new THREE.Vector3(93.164, 0.85, -12.962),
+      isSpread: true,
+      spreadDirection: 1, // 1是由小变大,-1是由大变小
+    },
+  ];
+
+  const downCurve = [
+    {
+      path0: new THREE.Vector3(-94.84, -0.388, 3.61),
+      path1: new THREE.Vector3(-85.678, -0.393, 3.61),
+      isSpread: true,
+      spreadDirection: -1, //
+    },
+    {
+      path0: new THREE.Vector3(-85.678, -0.393, 3.275),
+      path1: new THREE.Vector3(-85.636, -0.392, -3.829),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(-85.636, -0.392, -3.829),
+      path1: new THREE.Vector3(-85.636, 0.926, -5.881),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(-85.636, 1.026, -5.881),
+      path1: new THREE.Vector3(-85.618, 0.887, -12.862),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(-85.618, 0.887, -12.962),
+      path1: new THREE.Vector3(80.404, 0.887, -12.962),
+      isSpread: false,
+      spreadDirection: 0,
+    },
+    {
+      path0: new THREE.Vector3(80.404, 0.887, -12.962),
+      path1: new THREE.Vector3(93.164, 0.91, -12.962),
+      isSpread: true,
+      spreadDirection: 1, // 1是由小变大,-1是由大变小
+    },
+  ];
+
+  const returnCurve = [
+    {
+      path0: new THREE.Vector3(93.164, 0.85, -12.962),
+      path1: new THREE.Vector3(86.39, 0.827, -12.962),
+      isSpread: false,
+      spreadDirection: 2,
+    },
+    {
+      path0: new THREE.Vector3(86.39, 0.827, -12.962),
+      path1: new THREE.Vector3(83.341, 0.847, -17.658),
+      isSpread: false,
+      spreadDirection: 2,
+    },
+    {
+      path0: new THREE.Vector3(83.341, 0.847, -17.658),
+      path1: new THREE.Vector3(-29.077, 0.847, -17.658),
+      isSpread: false,
+      spreadDirection: 2,
+    },
+    {
+      path0: new THREE.Vector3(-29.077, 0.847, -17.658),
+      path1: new THREE.Vector3(-29.64, 0.827, -39.047),
+      isSpread: false,
+      spreadDirection: 2,
+    },
+  ];
+
+  if (!topSmoke) {
+    topSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.75, 0.5, 400);
+    topSmoke.setPath(topCurve);
+    await topSmoke.setPoints();
+    group?.add(topSmoke.points);
+  }
+  if (!downSmoke) {
+    downSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 0, 0.75, 0.5, 400);
+    downSmoke.setPath(downCurve);
+    await downSmoke.setPoints();
+    group?.add(downSmoke.points);
+  }
+
+  if (!returnSmoke) {
+    returnSmoke = new Smoke('/model/img/texture-smoke.png', '#777777', 0, 0.35, 1.5, 200);
+    returnSmoke.setPath(returnCurve);
+    await returnSmoke.setPoints();
+    group?.add(returnSmoke.points);
+  }
+};
+
+const runFly = (deviceType, state) => {
+  if (state === 'open') {
+    if (deviceType === 'top') {
+      if (downSmoke && downSmoke.frameId) {
+        downSmoke.stopSmoke();
+      }
+      if (topSmoke && !topSmoke.frameId) {
+        topSmoke.startSmoke();
+      }
+    } else {
+      if (topSmoke && topSmoke.frameId) {
+        topSmoke.stopSmoke();
+      }
+      if (downSmoke && !downSmoke.frameId) {
+        downSmoke.startSmoke();
+      }
+    }
+    if (returnSmoke && !returnSmoke.frameId) {
+      returnSmoke?.startSmoke();
+    }
+  } else {
+    if (deviceType === 'top') {
+      if (topSmoke && topSmoke.frameId) {
+        topSmoke.stopSmoke();
+      }
+    } else {
+      if (downSmoke && downSmoke.frameId) {
+        downSmoke.stopSmoke();
+      }
+    }
+  }
+  if (deviceType === 'all' && state === 'close') {
+    returnSmoke?.stopSmoke();
+  }
+};
+
+// 调频 30-50 (life 300 - 800) , 25 = (800 - 300)/ 20
+const setSmokeFrequency = (deviceType, frequency) => {
+  const life = (frequency - 30) * 25;
+  let duration = 0;
+  let smoke;
+
+  if (deviceType === 'top') {
+    if (topLife == life) {
+      return;
+    }
+    topLife = life;
+    smoke = topSmoke;
+    duration = (Math.abs(life - smoke.life) / 500) * 25;
+  } else {
+    if (downLife == life) {
+      return;
+    }
+    downLife = life;
+    smoke = downSmoke;
+    duration = (Math.abs(life - smoke.life) / 500) * 25;
+  }
+  if (smoke) {
+    gsap.to(smoke, {
+      life: life,
+      duration: duration,
+      ease: 'easeInCubic',
+      overwrite: true,
+    });
+  }
+};
+
+const clearFly = () => {
+  if (topSmoke) topSmoke.clearSmoke();
+  if (downSmoke) downSmoke.clearSmoke();
+  if (returnSmoke) returnSmoke.clearSmoke();
+};
+// 初始化事件
+const startAnimation = () => {
+  // 定义鼠标点击事件
+  model.canvasContainer?.addEventListener('mousedown', mouseEvent.bind(null));
+  model.canvasContainer?.addEventListener('pointerup', mouseUp);
+};
+
+// 鼠标点击、松开事件
+const mouseEvent = (event) => {
+  if (event.button == 0) {
+    model?.canvasContainer?.addEventListener('mousemove', mousemove);
+    mouseDownFn(<UseThree>model, <THREE.Object3D>group, event, (intersects) => {
+      intersects.find((intersect) => {
+        const mesh = intersect.object;
+      });
+    });
+    console.log('摄像头控制信息', model?.orbitControls, model?.camera);
+  }
+};
+
+const mouseUp = () => {
+  if (!model) return;
+  mouseUpFn(model);
+  model.canvasContainer?.removeEventListener('mousemove', mousemove);
+};
+
+const mousemove = () => {
+  mousemoveFn();
+};
+
+export const mountedThree = (playerVal1) => {
+  player1 = playerVal1;
+  return new Promise((resolve) => {
+    // model = VENT_PARAM['simulatedPassword'] ? new UseThree('#fanLocal3D', '#fanLocal3DCSS') : new UseThree('#fanLocal3D');
+    model = new UseThree('#fanLocal3D', '#fanLocal3DCSS');
+    model.setEnvMap('test1');
+    model.renderer.toneMappingExposure = 1.0;
+    if (model.renderer) {
+      model.renderer.sortObjects = true;
+    }
+    resetCamera();
+    model.setGLTFModel([modelName]).then(async (gltf) => {
+      group = <THREE.Object3D>gltf[0];
+      const Fengtongbu01 = group?.getObjectByName('Cylinder1054') as THREE.Mesh;
+      if (Fengtongbu01) {
+        const textMaterial = new THREE.MeshBasicMaterial({
+          color: '#000',
+          transparent: true,
+          opacity: 0.3,
+          side: THREE.DoubleSide, // 这里是双面渲染的意思
+        });
+        Fengtongbu01.material = textMaterial;
+        Fengtongbu01.renderOrder = 300;
+      }
+
+      model?.scene?.add(group);
+      setModalPosition();
+      setControls();
+      await initFly();
+      model?.animate();
+      addLight(model?.scene);
+
+      fcFanObj = new fcFan(model);
+      await fcFanObj.mountedThree();
+
+      fmFanObj = new fmFan(model);
+      await fmFanObj.mountedThree();
+
+      startAnimation();
+      resolve(model);
+    });
+  });
+};
+
+export const destroy = () => {
+  if (model) {
+    model.isRender = false;
+    console.log('场景销毁后信息----------->', model.renderer?.info);
+    clearFly();
+    topSmoke = undefined;
+    downSmoke = undefined;
+    returnSmoke = undefined;
+    if (fcFanObj) fcFanObj.destroy();
+    if (fmFanObj) fmFanObj.destroy();
+    group = undefined;
+    model.destroy();
+    model = undefined;
+  }
+};

+ 33 - 0
src/views/vent/monitorManager/fanLocalMonitor1/fcfanLocal.three.ts

@@ -0,0 +1,33 @@
+import * as THREE from 'three';
+
+class fcFan {
+  model;
+  modelName = 'jbfj-fc';
+  group: THREE.Object3D | null = null;
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  mountedThree() {
+    if (!this.model) return;
+    return new Promise((resolve) => {
+      this.model.setGLTFModel([this.modelName]).then((gltf) => {
+        this.group = gltf[0];
+        if (this.group) {
+          this.group.name = this.modelName;
+          this.group.position.set(-0.056, -0.007, 3.494);
+        }
+
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+export default fcFan;

+ 29 - 0
src/views/vent/monitorManager/fanLocalMonitor1/fmfanLocal.three.ts

@@ -0,0 +1,29 @@
+import * as THREE from 'three';
+
+class fmFan {
+  model;
+  modelName = 'jbfj-fm';
+  group: THREE.Object3D | null = null;
+
+  constructor(model) {
+    this.model = model;
+  }
+  mountedThree() {
+    
+    return new Promise((resolve) => {
+      this.model.setGLTFModel([this.modelName]).then((gltf) => {
+        this.group = gltf[0];
+        if (this.group) this.group.name = this.modelName;
+        this.group?.position.set(-0.668, -0.037, -0.023);
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+export default fmFan;

+ 1553 - 0
src/views/vent/monitorManager/fanLocalMonitor1/index.vue

@@ -0,0 +1,1553 @@
+<template>
+  <div class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
+    <a-spin :spinning="loading" />
+    <div v-show="activeBtn == 'fanLocal-ssjc'" id="fanLocal3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
+    <div
+      v-show="activeBtn == 'fanLocal-ssjc'"
+      id="fanLocal3DCSS"
+      class="threejs-Object-CSS"
+      style="width: 100%; height: 100%; position: absolute; overflow: hidden; pointer-events: none"
+    >
+      <div style="z-index: -1; position: relative" v-if="hasPermission('show:sensorMonitor')">
+        <div class="elementTag" id="inputBox1">
+          <div class="elementContent" v-if="selectData.windSpeed1 || selectData.gas3 || selectData.windSpeed_merge">
+            <p v-if="selectData.windSpeed1 || selectData.windSpeed_merge"
+              >风筒入口风速:<span class="value">{{
+                selectData.windSpeed1 ? selectData.windSpeed1 : selectData.windSpeed_merge ? selectData.windSpeed_merge : '-'
+              }}</span>
+              <span class="unit"> m/s</span>
+            </p>
+            <p v-if="selectData.windInputSpeed1 || selectData.windInputSpeed_merge"
+              >风筒入口风速:<span class="value">{{
+                selectData.windInputSpeed1 ? selectData.windInputSpeed1 : selectData.windInputSpeed_merge ? selectData.windInputSpeed_merge : '-'
+              }}</span>
+              <span class="unit"> m/s</span>
+            </p>
+            <p v-if="selectData.windQuantity1 || selectData.inletAirVolume_merge"
+              >风筒入口风量:<span class="value">{{
+                selectData.windQuantity1 ? selectData.windQuantity1 : selectData.inletAirVolume_merge ? selectData.inletAirVolume_merge : '-'
+              }}</span>
+              <span class="unit"> m³/min</span>
+            </p>
+            <p v-if="selectData.gas3"
+              >风筒入口瓦斯浓度: <span class="value">{{ selectData.gas3 ? selectData.gas3 : '-' }}</span>
+              <span class="unit"> %</span>
+            </p>
+          </div>
+        </div>
+        <div class="elementTag" id="outBox">
+          <div
+            class="elementContent elementContent-r"
+            v-if="
+              selectData.windQuantity2 ||
+              selectData.gas1 ||
+              (selectData.windOutSpeed1 && selectData.windOutSpeed_merge) ||
+              selectData.ductOutletAirVolume_merge
+            "
+          >
+            <p v-if="selectData.windQuantity2 || selectData.m3 || selectData.ductOutletAirVolume_merge || selectData.windOutSpeed_merge">
+              迎头供风量:<span class="value">{{
+                selectData.windQuantity2
+                  ? selectData.windQuantity2
+                  : selectData.m3
+                  ? selectData.m3
+                  : selectData.ductOutletAirVolume_merge
+                  ? selectData.ductOutletAirVolume_merge
+                  : '-'
+              }}</span>
+              <span class="unit"> m³/min</span>
+            </p>
+            <p v-if="selectData.gas1"
+              >迎头瓦斯浓度:<span class="value">{{ selectData.gas1 ? selectData.gas1 : '-' }}</span>
+              <span class="unit"> %</span>
+            </p>
+            <p v-if="selectData.windOutSpeed1 || selectData.windOutSpeed_merge"
+              >风筒出口风速<span class="value">{{
+                selectData.windOutSpeed1 ? selectData.windOutSpeed1 : selectData.windOutSpeed_merge ? selectData.windOutSpeed_merge : '-'
+              }}</span>
+              <span class="unit"> %</span>
+            </p>
+          </div>
+        </div>
+        <div class="elementTag" id="returnBox">
+          <div class="elementContent elementContent-r" v-if="selectData.gas2">
+            <p v-if="selectData.gas2"
+              >回风流瓦斯浓度:<span class="value">{{ selectData.gas2 ? selectData.gas2 : '-' }}</span>
+              <span class="unit"> %</span>
+            </p>
+          </div>
+        </div>
+        <div class="elementTag" id="gateBox">
+          <div class="elementContent">
+            <p>风门状态:关</p>
+            <p>风门过风面积:{{ selectData.gas1 ? selectData.gas1 : '-' }}</p>
+          </div>
+        </div>
+        <div class="elementTag" id="windownBox">
+          <div class="elementContent" v-if="modalType == 'fc'">
+            <p style="pointer-events: auto"
+              ><a class="action-link" @click="goDetailDevice('window_fWindowM3')">风窗详情</a>
+              <ArrowRightOutlined :style="{ color: '#157DC8' }" />
+            </p>
+            <p v-if="selectData.windSpeed"
+              >风窗风流风速:<span class="value">{{ selectData.windSpeed ? selectData.windSpeed : '-' }}</span> <span class="unit"> m/s</span></p
+            >
+            <p v-if="selectData.fWindowM3"
+              >风窗过风量:<span class="value">{{ selectData.fWindowM3 ? selectData.fWindowM3 : '-' }}</span> <span class="unit"> m³/min</span></p
+            >
+            <p v-if="selectData.OpenDegree"
+              >风窗开度值:<span class="value">{{ selectData.OpenDegree ? selectData.OpenDegree : '-' }}</span> <span class="unit"> %</span></p
+            >
+            <p v-if="selectData.OpenDegree"
+              >风窗过风面积:<span class="value">{{ selectData.forntArea ? selectData.forntArea : '-' }}</span> <span class="unit"> ㎡</span></p
+            >
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <div class="scene-box">
+    <div class="top-box" v-if="!loading && activeBtn == 'fanLocal-ssjc'">
+      <div class="top-center row">
+        <!-- <div class="vent-flex-row" id="fanLocalSelectDom" v-if="!globalConfig?.simulatedPassword && getDictItemsByCode('fanlocaltype')">
+          <span style="color: #00f5fe; margin-left: 5px">风机类型:</span>
+          <JDictSelectTag
+            style="width: 180px"
+            v-model:value="devicekide"
+            dictCode="fanlocaltype"
+            :showChooseOption="false"
+            :getPopupContainer="getPopupContainer"
+            @change="changeDeviceKind"
+          />
+        </div> -->
+        <!-- fanlocal_systeml_zj 模拟局部风机,不显示操作按钮 -->
+        <template v-for="(item, index) in modalTypeArr.leftBtnArr" :key="index">
+          <div
+            v-if="!(selectData.fanFrequencyType == 'fandp' && item.permission.startsWith('btn:frequency')) && hasPermission(item.permission)"
+            :class="{ 'button-box': btnClick, 'button-disable': !btnClick }"
+            @click="showModal(item)"
+            >{{ item.value }}
+          </div>
+        </template>
+      </div>
+      <div class="top-right row">
+        <template v-for="(item, index) in modalTypeArr.rightBtnArr" :key="index">
+          <div
+            v-if="
+              !(selectData.fanFrequencyType == 'fandp' && (item.permission === 'fanLocal:gasAlarmSet' || item.permission === 'fanLocal:kkjc')) &&
+              hasPermission(item.permission)
+            "
+            :class="{ 'button-box': btnClick, 'button-disable': !btnClick }"
+            @click="showModal(item)"
+            >{{ item.value }}</div
+          >
+        </template>
+      </div>
+    </div>
+    <div class="title-text">
+      {{ selectData.supplyAirAddr || selectData.strinstallpos || selectData.stationname }}
+    </div>
+    <div class="data-show-box" v-if="!loading && activeBtn == 'fanLocal-ssjc'">
+      <div class="data-item" v-if="leftColumns.length > 0">
+        <div class="item-header">设备监测</div>
+        <div class="item-container">
+          <div class="tab">
+            <div class="tab-item" :class="{ 'tab-item-active-r': warningMonitorRowIndex === 0 }" @click="selectDevice('warningMonitorRowIndex', 0)"
+              >主机</div
+            >
+            <div class="tab-item" :class="{ 'tab-item-active-r': warningMonitorRowIndex === 1 }" @click="selectDevice('warningMonitorRowIndex', 1)"
+              >备机</div
+            >
+          </div>
+          <div class="container-group">
+            <div class="warning-group">
+              <template v-if="selectData.deviceType">
+                <div class="container-item" v-for="(data, index) in leftColumns" :key="index">
+                  <div class="item-icon">
+                    <CaretRightOutlined class="icon-style" />
+                  </div>
+                  <div class="item-name">{{ data.title }}</div>
+                  <div v-if="data.dataIndex.startsWith('Fan')">
+                    <div class="item-value" v-if="warningMonitorRowIndex == 0">{{
+                      selectData[data.dataIndex.replace('Fan', 'Fan1')] ? selectData[data.dataIndex.replace('Fan', 'Fan1')] : '-'
+                    }}</div>
+                    <div class="item-value" v-if="warningMonitorRowIndex == 1">{{
+                      selectData[data.dataIndex.replace('Fan', 'Fan2')] ? selectData[data.dataIndex.replace('Fan', 'Fan2')] : '-'
+                    }}</div>
+                  </div>
+                  <div v-else>
+                    <div class="item-value">{{ selectData[data.dataIndex] ? selectData[data.dataIndex] : '-' }}</div>
+                  </div>
+                </div>
+              </template>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div>
+        <div class="data-item" v-if="rightColumns.length > 0">
+          <div class="item-header">环境监测/设备报警</div>
+          <div class="item-container">
+            <div class="tab">
+              <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 0 }" @click="selectDevice('dataMonitorRowIndex', 0)"
+                >主机</div
+              >
+              <div class="tab-item" :class="{ 'tab-item-active-r': dataMonitorRowIndex == 1 }" @click="selectDevice('dataMonitorRowIndex', 1)"
+                >备机</div
+              >
+            </div>
+            <div class="container-group container-group-l">
+              <div class="warning-group" style="max-height: 50%; overflow-y: auto">
+                <template v-if="deviceType">
+                  <div v-for="(state, index) in rightColumns" :key="index">
+                    <template v-if="!state.dataIndex.endsWith('_w')">
+                      <div class="container-item">
+                        <div class="item-icon">
+                          <CaretRightOutlined class="icon-style" />
+                        </div>
+                        <div class="item-name">{{ state.title }}</div>
+                        <div v-if="state.dataIndex.startsWith('Fan')">
+                          <div class="item-value" v-if="dataMonitorRowIndex == 0">{{
+                            selectData[state.dataIndex.replace('Fan', 'Fan1')] ? selectData[state.dataIndex.replace('Fan', 'Fan1')] : '-'
+                          }}</div>
+                          <div class="item-value" v-if="dataMonitorRowIndex == 1">{{
+                            selectData[state.dataIndex.replace('Fan', 'Fan2')] ? selectData[state.dataIndex.replace('Fan', 'Fan2')] : '-'
+                          }}</div>
+                        </div>
+                        <div v-else>
+                          <div class="item-value">{{ selectData[state.dataIndex] ? selectData[state.dataIndex] : '-' }} </div>
+                        </div>
+                      </div>
+                    </template>
+                  </div>
+                </template>
+              </div>
+              <div class="warning-group" style="max-height: 50%; overflow-y: auto">
+                <div class="warning-header">
+                  <div class="header-item">
+                    <div class="header-title">报警数量</div>
+                    <div class="header-value">{{ selectData['warnLogNotOkCount'] }} </div>
+                  </div>
+                </div>
+                <template v-if="deviceType">
+                  <div v-for="(state, index) in leftColumns" :key="index">
+                    <template v-if="state.dataIndex.endsWith('_w')">
+                      <div class="warning-item">
+                        <div class="item-name"> <div class="icon"></div> {{ state.title }} </div>
+                        <div v-if="state.dataIndex.startsWith('Fan')">
+                          <div class="signal-item" v-if="warningMonitorRowIndex == 0">
+                            <div
+                              class="signal-round"
+                              :class="{
+                                'signal-round-run': selectData[state.dataIndex.replace('Fan', 'Fan1')] == '0',
+                                'signal-round-warning':
+                                  selectData[state.dataIndex.replace('Fan', 'Fan1')] !== undefined &&
+                                  selectData[state.dataIndex.replace('Fan', 'Fan1')] == '1',
+                                'signal-round-gry': selectData[state.dataIndex.replace('Fan', 'Fan1')] === undefined,
+                              }"
+                            ></div>
+                            <div class="vent-margin-l-8">{{
+                              selectData[state.dataIndex.replace('Fan', 'Fan1')] === undefined
+                                ? '无状态'
+                                : selectData[state.dataIndex.replace('Fan', 'Fan1')] == '0'
+                                ? '正常'
+                                : '异常'
+                            }}</div>
+                          </div>
+                          <div class="signal-item" v-if="warningMonitorRowIndex == 1">
+                            <div
+                              class="signal-round"
+                              :class="{
+                                'signal-round-run': selectData[state.dataIndex.replace('Fan', 'Fan2')] == '0',
+                                'signal-round-warning':
+                                  selectData[state.dataIndex.replace('Fan', 'Fan2')] != undefined &&
+                                  selectData[state.dataIndex.replace('Fan', 'Fan2')] == '1',
+                                'signal-round-gry': selectData[state.dataIndex.replace('Fan', 'Fan2')] == undefined,
+                              }"
+                            ></div>
+                            <div class="vent-margin-l-8">{{
+                              selectData[state.dataIndex.replace('Fan', 'Fan2')] == undefined
+                                ? '无状态'
+                                : selectData[state.dataIndex.replace('Fan', 'Fan2')] == '0'
+                                ? '正常'
+                                : '异常'
+                            }}</div>
+                          </div>
+                        </div>
+                        <div v-else>
+                          <div class="signal-item">
+                            <div
+                              class="signal-round vent-margin-l-8"
+                              :class="{
+                                'signal-round-run': selectData[state.dataIndex] == '0',
+                                'signal-round-warning': selectData[state.dataIndex] !== undefined && selectData[state.dataIndex] == '1',
+                                'signal-round-gry': selectData[state.dataIndex] === undefined,
+                              }"
+                            ></div>
+                            <div class="vent-margin-l-8">{{
+                              selectData[state.dataIndex] === undefined ? '无状态' : selectData[state.dataIndex] == '0' ? '正常' : '异常'
+                            }}</div>
+                          </div>
+                        </div>
+                      </div>
+                    </template>
+                  </div>
+                </template>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div
+    ref="playerRef"
+    :class="{ 'to-right': rightColumns.length < 1 || leftColumns.length < 1, 'to-no-right': rightColumns.length > 0 && leftColumns.length > 0 }"
+    style="z-index: 999; position: absolute; top: 100px; right: 15px; width: 100%; height: 100%; margin: auto; pointer-events: none"
+  >
+  </div>
+  <a-modal v-model:visible="modalIsShow" :title="modalTitle" :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }">
+    <template #footer>
+      <div v-if="controlType != 'startFan'">
+        <a-button key="back" @click="cancel">返回</a-button>
+        <a-button key="submit" type="primary" :loading="loading" @click="handleOk">确定</a-button>
+      </div>
+    </template>
+    <div class="modal-container">
+      <div class="vent-flex-row">
+        <ExclamationCircleFilled style="color: #ffb700; font-size: 30px" />
+        <div class="warning-text">您是否要进行{{ modalTitle }}操作?</div>
+      </div>
+      <div class="" v-if="controlType == 'startSmoke'">
+        <!-- 互斥控制 -->
+        <div class="startSmoke-select">
+          <div class="label">主机:</div>
+          <a-radio-group v-model:value="mainWindIsShow1" @change="changeMotor" name="localWind1">
+            <a-radio value="open">开启</a-radio>
+            <a-radio value="stop">停止</a-radio>
+          </a-radio-group>
+        </div>
+        <div class="startSmoke-select">
+          <div class="label">备机:</div>
+          <a-radio-group v-model:value="mainWindIsShow2" @change="changeMotor" name="localWind2">
+            <a-radio value="open">开启</a-radio>
+            <a-radio value="stop">停止</a-radio>
+          </a-radio-group>
+        </div>
+      </div>
+      <div class="" v-if="controlType == 'startFan'">
+        <!-- 不互斥控制 -->
+        <div class="startSmoke-select">
+          <div class="label">主机:</div>
+          <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1Open')">开启</div>
+          <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1Stop')">停止</div>
+          <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1Reset')">复位</div>
+        </div>
+        <div class="startSmoke-select">
+          <div class="label">备机:</div>
+          <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2Open')">开启</div>
+          <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2Stop')">停止</div>
+          <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2Reset')">复位</div>
+        </div>
+      </div>
+      <!-- 调频 -->
+      <div class="vent-flex-row input-box" v-if="controlType == 'Fan1Frequency'">
+        <div class="label">主风机运行频率(Hz):</div>
+        <a-input-number size="small" v-model:value="fan1FrequencyVal" :min="20" :max="50" :step="0.1" />
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'Fan2Frequency'">
+        <div class="label">备风机运行频率(Hz):</div>
+        <a-input-number size="small" v-model:value="fan2FrequencyVal" :min="20" :max="50" :step="0.1" />
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'FanFrequency'">
+        <div class="label">风机运行频率(Hz):</div>
+        <a-input-number size="small" v-model:value="fan1FrequencyVal" :min="20" :max="50" :step="0.1" />
+      </div>
+
+      <div class="vent-flex-row input-box" v-if="controlType == 'disAirAlarm'">
+        <div class="label">漏风率(%):</div>
+        <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" />
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'diameter'">
+        <div class="label">风筒直径(m):</div>
+        <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" />
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'len'">
+        <div class="label">风筒长度(m):</div>
+        <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" />
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'windPowerLimit'">
+        <div class="label">风电闭锁限值(m³/min):</div>
+        <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" />
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'gasPowerLimit'">
+        <div class="label">瓦斯电闭锁限值(m³/min):</div>
+        <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" />
+      </div>
+      <div v-if="controlType == 'gasAlarmSet'">
+        <div class="vent-flex-row input-box">
+          <div class="label">设置瓦斯超限浓度:</div>
+          <a-input-number size="small" v-model:value="gasWarningVal" :min="0" :max="1" :step="0.01" />
+        </div>
+      </div>
+      <div v-if="controlType == 'gasAlarm'">
+        <div class="vent-flex-row input-box">
+          <div class="label">传感器名称:</div>
+          <a-select placeholder="传感器" @change="handleChangeSensor" :options="sensorList" v-model:value="modalSensor" />
+        </div>
+        <div class="vent-flex-row input-box">
+          <div class="label">传感器值:</div>
+          <a-input-number size="small" v-model:value="frequencyVal" :min="0" :max="50" :step="0.1" />
+        </div>
+      </div>
+      <div v-if="controlType == 'airVolumeAlarm'">
+        <div class="vent-flex-row input-box">
+          <div class="label">风量上限(m³/min):</div>
+          <a-input-number size="small" v-model:value="modalTypeArr.rightBtnArr[3].min" :min="0" :max="50" :step="0.1" />
+        </div>
+        <div class="vent-flex-row input-box">
+          <div class="label">风量下限(m³/min):</div>
+          <a-input-number size="small" v-model:value="modalTypeArr.rightBtnArr[3].max" :min="0" :max="50" :step="0.1" />
+        </div>
+      </div>
+      <div class="vent-flex-row input-box" v-if="controlType == 'zhlk'">
+        <div class="label">目标风量(m³/min):</div>
+        <a-input-number size="small" v-model:value="targetVolume" />
+      </div>
+      <div v-if="controlType == 'gasOverSet'">
+        <div class="vent-flex-row input-box">
+          <div class="label">设置瓦斯超限浓度:</div>
+          <a-input-number size="small" v-model:value="gasWarningVal" :min="0" :max="1" :step="0.01" />
+        </div>
+      </div>
+      <!-- 启动或停止 -->
+      <div class="" v-if="controlType == 'startSmoke'"> </div>
+      <div v-if="!globalConfig?.simulatedPassword" class="vent-flex-row input-box">
+        <div class="label">操作密码:</div>
+        <a-input size="small" type="password" v-model:value="passWord" />
+      </div>
+    </div>
+  </a-modal>
+
+  <fanlocalHistory v-if="activeBtn == 'fanLocal-history'" :selectData="selectData" :devicekide="devicekide" />
+  <fanlocalWarnHistory v-if="activeBtn == 'fanLocal-warn'" :devicekide="devicekide" />
+  <fanlocalOperateHistory v-if="activeBtn == 'fanLocal-operate'" :devicekide="devicekide" />
+  <fanlocalEchartLine v-if="activeBtn == 'fanLocal-wind'" :historyList="historyList" :chartsColumns="chartsColumns" />
+  <BottomMenu :nav-list="navList" @change="changeActive" />
+</template>
+
+<script setup lang="ts">
+  import { ExclamationCircleFilled, ArrowRightOutlined } from '@ant-design/icons-vue';
+  import { onBeforeMount, ref, watch, onMounted, nextTick, defineAsyncComponent, reactive, onUnmounted, inject, unref } from 'vue';
+  import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
+  import fanlocalHistory from './components/fanlocal-history.vue';
+  import fanlocalWarnHistory from './components/fanlocal-warn-history.vue';
+  import fanlocalOperateHistory from './components/fanlocal-operate-history.vue';
+  import fanlocalEchartLine from './components/fanlocal-echart-line.vue';
+  import { mountedThree, setModelType, destroy, addCssText, addText, playSmoke } from './fanLocal.three';
+  import lodash from 'lodash';
+  import { getTableList, list, autoAdjust } from '/@/views/vent/monitorManager/fanLocalMonitor/fanLocal.api';
+  import { chartsColumns1, navList } from './fanLocal.data';
+  import { deviceControlApi } from '/@/api/vent/index';
+  import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
+  import { useRouter } from 'vue-router';
+  import type { BasicColumn } from '/@/components/Table/src/types/table';
+  import JDictSelectTag from '/@/components/Form/src/jeecg/components/JDictSelectTag.vue';
+  import { getPopupContainer } from '/@/utils';
+  import { getDictItemsByCode } from '/@/utils/dict';
+  import { message } from 'ant-design-vue';
+  import { useCamera } from '/@/hooks/system/useCamera';
+  import { CaretRightOutlined } from '@ant-design/icons-vue';
+  import { usePermission } from '/@/hooks/web/usePermission';
+  import { useGlobSetting } from '/@/hooks/setting';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  const globalConfig = inject('globalConfig');
+
+  const { hasPermission } = usePermission();
+
+  const { currentRoute } = useRouter();
+  const router = useRouter();
+  const { createConfirm } = useMessage();
+  const globSetting = useGlobSetting();
+
+  const modalTypeArr = reactive({
+    leftBtnArr: [
+      {
+        key: 'startSmoke',
+        value: '启停风机',
+        permission: 'btn:openclose',
+      },
+      {
+        key: 'startFan',
+        value: '启停风机',
+        permission: 'btn:openclose1',
+      },
+      {
+        key: 'changeSmoke', // 主备两个点位
+        value: '一键倒机',
+        permission: 'btn:change',
+      },
+      {
+        key: 'changeFan', // 主备一个点位
+        value: '一键倒机',
+        permission: 'btn:CtrlFanChange',
+      },
+      {
+        key: 'fan1ToFan2',
+        value: '主机倒备机',
+        permission: 'btn:ctrlFan1ToFan2',
+      },
+      {
+        key: 'fan2ToFan1',
+        value: '备机倒主机',
+        permission: 'btn:ctrlFan2ToFan1',
+      },
+      {
+        key: 'Fan1Frequency',
+        value: '主机调频',
+        permission: 'btn:frequency',
+      },
+      {
+        key: 'Fan2Frequency',
+        value: '备机调频',
+        permission: 'btn:frequency',
+      },
+      {
+        key: 'FanFrequency',
+        value: '风机调频',
+        permission: 'btn:frequencyMerge',
+      },
+      {
+        key: 'windPower',
+        value: '风电闭锁',
+        permission: 'fanLocal:fdbs',
+      },
+      {
+        key: 'gasPower',
+        value: '瓦斯电闭锁',
+        permission: 'fanLocal:wsdbs',
+      },
+      {
+        key: 'needAir',
+        value: '需风量',
+        permission: 'fanLocal:control',
+      },
+    ],
+    rightBtnArr: [
+      {
+        key: 'gasAlarmSet',
+        value: '瓦斯限值设定',
+        permission: 'fanLocal:gasAlarmSet',
+      },
+      {
+        key: 'gasOverSet', //
+        value: '瓦斯限值设定',
+        permission: 'fanLocal:gasOverSet',
+      },
+      {
+        key: 'kkjc',
+        value: '工况辅助决策',
+        permission: 'fanLocal:kkjc',
+      },
+      {
+        key: 'zhlk',
+        value: '自主联控',
+        permission: 'fanLocal:zhlk',
+      },
+      {
+        key: 'diameter',
+        value: '风筒直径',
+        permission: 'fanLocal:control',
+      },
+      {
+        key: 'diameter',
+        value: '风筒直径',
+        permission: 'fanLocal:control',
+      },
+      {
+        key: 'len',
+        value: '风筒长度',
+        permission: 'fanLocal:control',
+      },
+      // {
+      //   key: 'frequency',
+      //   value: '调频',
+      //   permission: 'fanLocal:control',
+      // },
+      {
+        key: 'windPowerLimit',
+        value: '风电闭锁限值',
+        permission: 'fanLocal:control',
+      },
+      {
+        key: 'gasPowerLimit',
+        value: '瓦斯电闭锁限值',
+        permission: 'fanLocal:control',
+      },
+      {
+        key: 'airVolumeAlarm',
+        value: '风量报警',
+        permission: 'fanLocal:control',
+        min: 0,
+        max: 100,
+      },
+      {
+        key: 'disAirAlarm',
+        value: '漏风率报警',
+        permission: 'fanLocal:control',
+      },
+      // {
+      //   key: 'gasAlarm',
+      //   value: '瓦斯报警',
+      //   permission: 'fanLocal:control',
+      // },
+    ],
+  });
+  const sensorList = ref<any[]>([
+    {
+      value: '1',
+      label: 'T1',
+    },
+    {
+      value: '2',
+      label: 'T2',
+    },
+    {
+      value: '3',
+      label: 'T3',
+    },
+  ]);
+
+  const scroll = reactive({
+    y: 180,
+  });
+  const deviceTypeDicts = getDictItemsByCode('fanlocaltype');
+  const gasWarningVal = ref(0.6); // 瓦斯最大报警值
+  const playerRef = ref();
+  const modalSensor = ref(null);
+  const loading = ref(false);
+  const player1 = ref();
+  const modalIsShow = ref<boolean>(false); // 是否显示模态框
+  const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
+  const fan1FrequencyVal = ref(40); //主机频率
+  const fan2FrequencyVal = ref(40); //备机频率
+  const mainWindIsShow1 = ref('open'); // 主机默认启动leftColumns
+  const mainWindIsShow2 = ref('stop'); // 备机默认不启动
+  const fanControl = ref('');
+  const targetVolume = ref(600);
+  const historyList = ref([]);
+  const remoteChartsColumns = getTableHeaderColumns('fanlocal_chart');
+  const chartsColumns = remoteChartsColumns && remoteChartsColumns.length > 0 ? remoteChartsColumns : chartsColumns1;
+
+  const passWord = ref('');
+  // 默认初始是第一行
+  const selectRowIndex = ref(0);
+  const dataMonitorRowIndex = ref(0);
+  // 默认数据右边监测的是主机
+  const warningMonitorRowIndex = ref(0);
+
+  const xAxisDataGas = ref([]);
+  // 设备数据
+  const controlType = ref('');
+  const modalType = ref('');
+  // 监测数据
+  const initData = {
+    deviceID: '',
+    deviceType: '',
+    strname: '',
+    dataDh: '-', //压差
+    dataDtestq: '-', //测试风量
+    sourcePressure: '-', //气源压力
+    dataDequivalarea: '-',
+    netStatus: '0', //通信状态
+    warnLevel_str: '',
+    stationname: '',
+    fanFrequencyType: '',
+  };
+  const frequencyVal = ref(0);
+  const dataSource = ref([]);
+  // const historySource = ref([]);
+  // 关联设备信息
+  const linkDeviceInfo = ref({});
+  // 监测数据
+  let selectData = reactive(lodash.cloneDeep(initData));
+  const rightColumns = ref<BasicColumn[]>([]);
+  const leftColumns = ref<BasicColumn[]>([]);
+  const devicekide = ref('');
+  const deviceType = ref(selectData.deviceType);
+  const headElHeight = ref(0);
+  let btnClick = ref(true); // 判断按钮是否可点
+
+  //报表导出
+  // let editID = ref<any>('');
+  // let fileType = ref('');
+
+  const { getCamera, removeCamera } = useCamera();
+
+  watch(deviceType, (type) => {
+    rightColumns.value = getTableHeaderColumns(type + '_monitor_right') as [];
+    if (rightColumns.value && rightColumns.value.length < 1) {
+      rightColumns.value = getTableHeaderColumns(type.split('_')[0] + '_monitor_right') as [];
+    }
+    leftColumns.value = getTableHeaderColumns(type + '_monitor_left') as [];
+    if (leftColumns.value && leftColumns.value.length < 1) {
+      leftColumns.value = getTableHeaderColumns(type.split('_')[0] + '_monitor_left') as [];
+    }
+  });
+
+  const flvURL1 = () => {
+    // return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`;
+    return '';
+  };
+
+  const activeBtn = ref('fanLocal-ssjc');
+  function changeActive(activeValue) {
+    activeBtn.value = activeValue;
+  }
+
+  const selectDevice = (key, val) => {
+    if (key === 'dataMonitorRowIndex') {
+      dataMonitorRowIndex.value = val;
+    } else {
+      warningMonitorRowIndex.value = val;
+    }
+  };
+
+  function goDetailDevice(linkDeviceCode) {
+    let linkDeviceId = '';
+    if (linkDeviceCode.startsWith('window')) {
+      linkDeviceId = linkDeviceInfo.value[linkDeviceCode] ? linkDeviceInfo.value[linkDeviceCode]['id'] : '';
+      router.push({ path: '/monitorChannel/monitor-window', query: { id: linkDeviceId } });
+    }
+  }
+
+  //
+  async function getDataSource() {
+    if (devicekide.value) {
+      const res = await list({ devicetype: devicekide.value, pagetype: 'normal' });
+      // const res = await list({ devicetype: 'fanlocal', pagetype: 'normal' });
+      if (res.msgTxt && res.msgTxt[0] && res.msgTxt[0].datalist && res.msgTxt[0].datalist.length > 0) {
+        const dataArr = res.msgTxt[0].datalist || [];
+        dataSource.value = [];
+        dataArr.forEach((data) => {
+          const readData = data.readData;
+          data = Object.assign(data, readData);
+          if (data['Fan1StartStatus'] && data['Fan1StartStatus'] === '1.0') data['Fan1StartStatus'] = '1';
+          if (data['Fan2StartStatus'] && data['Fan2StartStatus'] === '1.0') data['Fan2StartStatus'] = '1';
+          if (data['Fan1StartStatus'] && data['Fan1StartStatus'] === '0.0') data['Fan1StartStatus'] = '0';
+          if (data['Fan2StartStatus'] && data['Fan2StartStatus'] === '0.0') data['Fan2StartStatus'] = '0';
+          data['windQuantity2'] =
+            data['windQuantity2'] ||
+            data['m3'] ||
+            data['ductOutletAirVolume_merge'] ||
+            data['windOutSpeed_merge'] ||
+            data['windOutSpeed1'] ||
+            data['windOutSpeed2'] ||
+            data['windOutSpeed_merge'];
+          // if (globSetting.sysOrgCode === 'sdmtjtbetmk') {
+          //   if (data['m3']) data['ductOutletAirVolume_merge'] = data['m3'];
+          //   if (data['m3']) data['inletAirVolume_merge'] = (Number(data['m3']) * 1.08).toFixed(2);
+          // }
+          dataSource.value.push(data);
+          if (selectRowIndex.value > -1) {
+            let echartsData = dataArr[selectRowIndex.value]['history'] || [];
+            echartsData = echartsData.filter((item) => {
+              item['FanfHz'] = data['Fan1StartStatus'] == '1' ? item['Fan1fHz'] : data['Fan2StartStatus'] == '1' ? item['Fan2fHz'] : 0;
+              item['windQuantity2'] =
+                item['windQuantity2'] ||
+                item['m3'] ||
+                item['ductOutletAirVolume_merge'] ||
+                item['windOutSpeed_merge'] ||
+                item['windOutSpeed1'] ||
+                item['windOutSpeed2'] ||
+                item['windOutSpeed_merge'];
+              return true;
+            });
+            historyList.value = echartsData;
+          }
+        });
+      } else {
+        return (dataSource.value = []);
+      }
+    } else {
+      dataSource.value = [];
+    }
+  }
+
+  // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  async function getMonitor(flag?) {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = await setTimeout(
+        async () => {
+          // debugger;
+          await getDataSource();
+          for (const key in selectData) {
+            selectData[key] = '';
+          }
+          if (dataSource.value.length > 0 && dataSource.value[selectRowIndex.value]) {
+            deviceType.value = dataSource.value[selectRowIndex.value]['deviceType'];
+            if (dataSource.value.length > 0 && dataSource.value[selectRowIndex.value]) {
+              Object.assign(selectData, dataSource.value[selectRowIndex.value]);
+            }
+            playSmoke(selectData);
+            addText(selectData);
+          }
+          // historySource.value = selectData.history;
+          if (timer) {
+            timer = null;
+          }
+          getMonitor();
+        },
+        flag ? 0 : 1000
+      );
+    }
+  }
+
+  // 获取设备基本信息列表
+  const deviceBaseList = ref([]);
+  function getDeviceBaseList() {
+    getTableList({ pageSize: 1000 }).then((res) => {
+      deviceBaseList.value = res.records;
+    });
+  }
+
+  // 打开并设置modal的标题
+  function showModal(obj) {
+    if (!btnClick.value) return;
+    if (obj.key == 'kkjc') {
+      gasWarningVal.value = 0.6;
+      // 工况辅助决策
+      openAssistance(true, {});
+      return;
+    }
+    controlType.value = obj.key;
+    modalTitle.value = obj.value;
+    passWord.value = '';
+    modalIsShow.value = true;
+  }
+
+  function changeMotor(e) {
+    const target = e.target;
+    if (target.name === 'localWind1') {
+      if (target.value === 'open') {
+        mainWindIsShow2.value = 'stop';
+      }
+    } else if (target.name === 'localWind2') {
+      if (target.value === 'open') {
+        mainWindIsShow1.value = 'stop';
+      }
+    }
+  }
+
+  function handleOk(control?) {
+    if (passWord.value == '') {
+      message.warning('请输入密码!');
+      return;
+    }
+
+    createConfirm({
+      iconType: 'warning',
+      title: '控制',
+      content: '您确定要控制吗?',
+      onOk: () => handerFn(),
+    });
+    const handerFn = () => {
+      const handType = controlType.value;
+      const data = {
+        deviceid: selectData.deviceID,
+        devicetype: selectData.deviceType,
+        paramcode: '',
+        password: passWord.value || globalConfig?.simulatedPassword,
+        value: null,
+      };
+      if (handType === 'startSmoke') {
+        // 启动风机
+        // 以下是互斥
+        if (mainWindIsShow1.value === 'open' && mainWindIsShow2.value === 'stop') {
+          // playSmoke(handType, 'top', frequency, 'open');
+          data.paramcode = 'CtrlFan1Start';
+          deviceControlApi(data)
+            .then((res) => {
+              if (res.success) {
+                if (globalConfig.History_Type == 'remote') {
+                  message.success('指令已下发至生产管控平台成功!');
+                } else {
+                  message.success('指令已下发成功!');
+                }
+                modalTitle.value = '';
+                modalIsShow.value = false;
+              } else {
+                message.error(res.message);
+              }
+            })
+            .catch((err) => {
+              // modalIsShow.value = true;
+            });
+        } else if (mainWindIsShow2.value === 'open' && mainWindIsShow1.value === 'stop') {
+          // playSmoke(handType, 'down', frequency, 'open');
+          data.paramcode = 'CtrlFan2Start';
+          deviceControlApi(data)
+            .then(() => {
+              if (res.success) {
+                if (globalConfig.History_Type == 'remote') {
+                  message.success('指令已下发至生产管控平台成功!');
+                } else {
+                  message.success('指令已下发成功!');
+                }
+                modalTitle.value = '';
+                modalIsShow.value = false;
+              } else {
+                message.error(res.message);
+              }
+            })
+            .catch((err) => {});
+        } else if (mainWindIsShow1.value === 'stop' && mainWindIsShow2.value === 'stop') {
+          // playSmoke(handType, '', frequency, 'stop');
+        }
+      } else if (handType === 'startFan') {
+        if (control === 'Fan1Open') {
+          data.paramcode = 'CtrlFan1Start';
+        } else if (control === 'Fan2Open') {
+          data.paramcode = 'CtrlFan2Start';
+        } else if (control === 'Fan1Stop') {
+          data.paramcode = 'Fan1Stop';
+        } else if (control === 'Fan2Stop') {
+          data.paramcode = 'Fan2Stop';
+        } else if (control === 'Fan1Reset') {
+          data.paramcode = 'Fan1Reset';
+        } else if (control === 'Fan2Reset') {
+          data.paramcode = 'Fan2Reset';
+        }
+        deviceControlApi(data)
+          .then((res) => {
+            if (res.success) {
+              if (globalConfig.History_Type == 'remote') {
+                message.success('指令已下发至生产管控平台成功!');
+              } else {
+                message.success('指令已下发成功!');
+              }
+              modalTitle.value = '';
+              modalIsShow.value = false;
+            } else {
+              message.error(res.message);
+            }
+          })
+          .catch((err) => {
+            btnClick.value = true;
+          });
+      } else if (handType === 'Fan1Frequency' || handType === 'Fan2Frequency' || handType === 'FanFrequency') {
+        // 调频
+        if (handType === 'Fan1Frequency') {
+          data.paramcode = 'Fan1FreqHz';
+          data.value = fan1FrequencyVal.value;
+        } else if (handType === 'Fan2Frequency') {
+          data.paramcode = 'Fan2FreqHz';
+          data.value = fan2FrequencyVal.value;
+        } else if (handType === 'FanFrequency') {
+          data.paramcode = 'FreqHz_merge';
+          data.value = fan1FrequencyVal.value;
+        }
+
+        deviceControlApi(data)
+          .then((res) => {
+            if (res.success) {
+              if (globalConfig.History_Type == 'remote') {
+                message.success('指令已下发至生产管控平台成功!');
+              } else {
+                message.success('指令已下发成功!');
+              }
+              modalTitle.value = '';
+              modalIsShow.value = false;
+            } else {
+              message.error(res.message);
+            }
+          })
+          .catch((err) => {});
+      } else if (handType === 'changeSmoke') {
+        if (selectData['Fan1StartStatus'] == '0' || !selectData['Fan1StartStatus']) {
+          data.paramcode = 'CtrlFan1Start';
+          deviceControlApi(data)
+            .then((res) => {
+              if (res.success) {
+                if (globalConfig.History_Type == 'remote') {
+                  message.success('指令已下发至生产管控平台成功!');
+                } else {
+                  message.success('指令已下发成功!');
+                }
+                modalTitle.value = '';
+                modalIsShow.value = false;
+              } else {
+                message.error(res.message);
+              }
+
+              mainWindIsShow1.value = 'stop';
+              mainWindIsShow2.value = 'open';
+            })
+            .catch((err) => {});
+        } else if (selectData['Fan2StartStatus'] == '0' || !selectData['Fan2StartStatus']) {
+          data.paramcode = 'CtrlFan2Start';
+          deviceControlApi(data)
+            .then((res) => {
+              if (res.success) {
+                if (globalConfig.History_Type == 'remote') {
+                  message.success('指令已下发至生产管控平台成功!');
+                } else {
+                  message.success('指令已下发成功!');
+                }
+                modalTitle.value = '';
+                modalIsShow.value = false;
+              } else {
+                message.error(res.message);
+              }
+              mainWindIsShow1.value = 'open';
+              mainWindIsShow2.value = 'stop';
+            })
+            .catch((err) => {});
+        }
+        // // 一键倒机
+        // if (mainWindIsShow1.value === 'open' && mainWindIsShow2.value === 'stop') {
+        //   // playSmoke('startSmoke', 'down', frequency, 'open');
+        //   data.paramcode = 'CtrlFan2Start';
+        //   deviceControlApi(data).then((res) => {
+        //     console.log('设备操作结果', res);
+        //     modalTitle.value = '';
+        //     modalIsShow.value = false;
+        //   }).catch((err) => {
+
+        //   });
+        //   mainWindIsShow1.value = 'stop';
+        //   mainWindIsShow2.value = 'open';
+        // } else if (mainWindIsShow2.value === 'open' && mainWindIsShow1.value === 'stop') {
+        //   // playSmoke('startSmoke', 'top', frequency, 'open');
+        //   data.paramcode = 'CtrlFan1Start';
+        //   deviceControlApi(data).then((res) => {
+        //     console.log('设备操作结果', res);
+        //     modalTitle.value = '';
+        //     modalIsShow.value = false;
+        //   }).catch((err) => {
+
+        //   });
+        //   mainWindIsShow1.value = 'open';
+        //   mainWindIsShow2.value = 'stop';
+        // } else if (mainWindIsShow1.value === 'stop' && mainWindIsShow2.value === 'stop') {
+        //   // playSmoke(handType, '', frequency, 'stop');
+        // }
+      } else if (handType === 'changeFan') {
+        data.paramcode = 'CtrlFanStart';
+        deviceControlApi(data)
+          .then((res) => {
+            if (res.success) {
+              if (globalConfig.History_Type == 'remote') {
+                message.success('指令已下发至生产管控平台成功!');
+              } else {
+                message.success('指令已下发成功!');
+              }
+            } else {
+              message.error(res.message);
+            }
+            modalTitle.value = '';
+            modalIsShow.value = false;
+          })
+          .catch((err) => {});
+      } else if (handType === 'fan1ToFan2') {
+        data.paramcode = 'CtrlFan1ToFan2';
+        deviceControlApi(data).then((res) => {
+          if (res.success) {
+            if (globalConfig.History_Type == 'remote') {
+              message.success('指令已下发至生产管控平台成功!');
+            } else {
+              message.success('指令已下发成功!');
+            }
+            modalTitle.value = '';
+            modalIsShow.value = false;
+          } else {
+            message.error(res.message);
+          }
+        });
+      } else if (handType === 'fan2ToFan1') {
+        data.paramcode = 'CtrlFan2ToFan1';
+        deviceControlApi(data).then((res) => {
+          if (res.success) {
+            if (globalConfig.History_Type == 'remote') {
+              message.success('指令已下发至生产管控平台成功!');
+            } else {
+              message.success('指令已下发成功!');
+            }
+            modalTitle.value = '';
+            modalIsShow.value = false;
+          } else {
+            message.error(res.message);
+          }
+        });
+      } else if (handType === 'gasAlarmSet') {
+        if (passWord.value != '123456') {
+          message.error('密码错误,请重新输入!');
+          return;
+        }
+        if (gasWarningVal.value) {
+          modalTitle.value = '';
+          modalIsShow.value = false;
+          setTimeout(() => {
+            passWord.value = '';
+            modalIsShow.value = true;
+            controlType.value = 'toGkjc';
+            modalTitle.value = '工况决策辅助';
+          }, 500);
+        } else {
+          message.error('请核对瓦斯超限浓度值!');
+        }
+      } else if (handType === 'toGkjc') {
+        if (passWord.value != '123456') {
+          message.error('密码错误,请重新输入!');
+          return;
+        }
+        //进行工况决策
+        if (selectData.Fan1StartStatus == '1') {
+          openAssistance(true, {
+            // m3: selectData.m3 || 675.87,
+            m3: 675.87,
+            frequency: 30,
+            // m3: 525.87,  //5.0测试数据
+            // frequency: 35,
+            // frequency: selectData.Fan1fHz || selectData.Fan1FreqHz || selectData.Fan1Loop_Frequency,
+            gasWarningVal: gasWarningVal.value,
+            isCompute: false,
+          });
+        } else if (selectData.Fan2StartStatus == '1') {
+          openAssistance(true, {
+            // m3: selectData.m3 || 675.87,
+            m3: 675.87,
+            frequency: 30,
+            // frequency: selectData.Fan2fHz || selectData.Fan2FreqHz || selectData.Fan2Loop_Frequency,
+            gasWarningVal: gasWarningVal.value,
+            isCompute: false,
+          });
+        } else {
+          // openAssistance(true, { m3: 635.04, dataDh: 5748 });
+          openAssistance(true);
+        }
+        modalTitle.value = '';
+        modalIsShow.value = false;
+      } else if (handType === 'zhlk' || handType === 'gasOverSet') {
+        if (targetVolume.value) {
+          const params =
+            handType === 'zhlk'
+              ? { auto: 1, fanlocalId: selectData.deviceID, xufengliang: targetVolume.value }
+              : { auto: 1, fanlocalId: selectData.deviceID, gasMax: gasWarningVal.value };
+          autoAdjust(params).then(() => {
+            if (res.success) {
+              if (globalConfig.History_Type == 'remote') {
+                message.success('指令已下发至生产管控平台成功!');
+              } else {
+                message.success('指令已下发成功!');
+              }
+              modalTitle.value = '';
+              modalIsShow.value = false;
+            } else {
+              message.error(res.message);
+            }
+          });
+        }
+      }
+    };
+  }
+
+  function cancel() {
+    modalTitle.value = '';
+    modalIsShow.value = false;
+    gasWarningVal.value = 0;
+  }
+
+  function handleChangeSensor(value: string) {
+    console.log(value);
+  }
+
+  function addPlayVideo() {
+    if (player1.value && player1.value.play) {
+      if (!player1.value.paused()) player1.value.play();
+      document.body.removeEventListener('mousedown', addPlayVideo);
+    }
+  }
+
+  onBeforeMount(() => {
+    getDeviceBaseList();
+  });
+
+  onMounted(() => {
+    const { query } = unref(currentRoute);
+    if (query['deviceType']) devicekide.value = query['deviceType'] as string;
+    mountedThree(player1.value).then(async () => {
+      await getMonitor(true);
+      nextTick(async () => {
+        setModelType('');
+        addCssText();
+      });
+    });
+
+    document.body.addEventListener('mousedown', addPlayVideo, false);
+  });
+
+  onUnmounted(() => {
+    destroy();
+    removeCamera();
+    if (timer) {
+      clearTimeout(timer);
+      timer = undefined;
+    }
+  });
+</script>
+<style scoped lang="less">
+  @import '/@/design/vent/modal.less';
+
+  :deep(.@{ventSpace}-tabs-tabpane-active) {
+    height: 100%;
+  }
+
+  .scene-box {
+    height: 100%;
+
+    .title-text {
+      height: 32px;
+    }
+  }
+
+  .data-show-box {
+    position: relative;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    padding: 10px 5px;
+    color: #ffffff;
+    z-index: 999;
+    top: 60px;
+
+    .data-item {
+      pointer-events: auto;
+
+      .item-header {
+        width: 374px;
+        background: url('/@/assets/images/vent/lr-top-bg.png') no-repeat;
+        background-size: auto;
+        height: 32px;
+        text-align: center;
+        line-height: 34px;
+        font-size: 15px;
+        font-weight: 600;
+        color: #fafafa;
+      }
+
+      .item-container {
+        height: 780px; //lxh
+        width: 346px;
+        margin: 0 14px;
+        padding: 10px;
+        background: #00377c33;
+        backdrop-filter: blur(2px);
+        overflow: hidden;
+
+        .tab {
+          width: 323px;
+          background: url('/@/assets/images/vent/lr-tab-bg.png') no-repeat;
+          display: flex;
+
+          .tab-item {
+            flex: 1;
+            text-align: center;
+            padding-top: 2px;
+            color: #ffffff99;
+            cursor: pointer;
+          }
+
+          .tab-item-active-l {
+            color: #00ffea;
+            background-image: url('/@/assets/images/vent/l-tab-active.png');
+            background-repeat: no-repeat;
+            background-size: auto;
+            background-position: 6px 3px;
+          }
+
+          .tab-item-active-r {
+            color: #00ffea;
+            background-image: url('/@/assets/images/vent/r-tab-active.png');
+            background-repeat: no-repeat;
+            background-position: 0 3px;
+          }
+        }
+
+        .container-group {
+          width: 314px;
+          height: calc(100% - 50px);
+          margin: 0px 4px;
+          padding: 10px 0;
+          min-height: 432px;
+          background: linear-gradient(to right, #00deff22, #2081ff05);
+          // max-height: 440px;lxh
+          overflow-y: auto;
+        }
+
+        .container-item {
+          width: 100%;
+          height: 60px;
+          display: flex;
+          padding: 10px 0 0 20px;
+          margin-bottom: 5px;
+          position: relative;
+          background: url('/@/assets/images/vent/plane-bottom.png') no-repeat;
+          background-size: auto;
+          background-position: bottom;
+
+          &::before {
+            content: '';
+            display: block;
+            width: 100%;
+            height: 5px;
+            position: absolute;
+            top: 62px;
+            left: 0;
+            background-color: #73f4ff66;
+            backdrop-filter: blur(5px);
+          }
+
+          .item-icon {
+            width: 54px;
+            height: 45px;
+            background: url('/@/assets/images/vent/plane-icon-bg.png') no-repeat;
+            background-size: cover;
+
+            .icon-style {
+              font-size: 18px;
+              margin: 10px 0 0 20px;
+              color: #ffc800;
+            }
+          }
+
+          .item-name {
+            width: 180px;
+            line-height: 60px;
+          }
+
+          .item-value {
+            position: relative;
+            height: 26px;
+            line-height: 24px;
+            margin: 15px 0;
+            text-align: center;
+            width: 80px;
+            border: 1px solid #00f5fe;
+            border-radius: 13px;
+            background: linear-gradient(to right, #00f5fe44, #0090ff44);
+
+            &::before {
+              width: 6px;
+              height: 6px;
+              content: '';
+              position: absolute;
+              left: -3px;
+              top: 8px;
+              background: #ffa500;
+              border-radius: 3px;
+            }
+          }
+        }
+
+        .warning-header {
+          display: flex;
+          font-size: 14px;
+
+          .header-item {
+            flex: 1;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+
+            .header-title {
+              color: #39e7fe;
+              margin-top: 10px;
+            }
+
+            .header-value {
+              // width: 133px;
+              height: 36px;
+              font-weight: 600;
+              font-family: 'douyuFont';
+              font-size: 16px;
+              color: #ffa500;
+              display: flex;
+              justify-content: center;
+              align-items: center;
+              margin-top: 15px;
+              margin-left: 8px;
+              // background: url('/@/assets/images/vent/count-header-bg.png') no-repeat;
+            }
+          }
+        }
+
+        .warning-group {
+          padding: 0 10px;
+          position: relative;
+
+          .warning-item {
+            display: flex;
+            flex-direction: row;
+            justify-content: space-between;
+            align-items: center;
+            height: 38px;
+
+            .item-name {
+              display: flex;
+              align-items: center;
+
+              // padding-left: 5px;
+              .icon {
+                width: 6px;
+                height: 6px;
+                display: inline-block;
+                background-color: #1cd5ff;
+                border-radius: 3px;
+                position: relative;
+                margin-right: 8px;
+
+                &::before {
+                  content: '';
+                  width: 10px;
+                  height: 10px;
+                  display: block;
+                  border: 1px solid #34edff99;
+                  border-radius: 5px;
+                  position: absolute;
+                  top: -2px;
+                  left: -2px;
+                }
+              }
+
+              &::before {
+                content: '';
+                display: block;
+                width: 1px;
+                height: 38px;
+                position: absolute;
+                left: 12px;
+                background-color: #00f5fe;
+              }
+            }
+          }
+        }
+
+        .warning-group-r {
+          &::before {
+            content: '';
+            display: block;
+            width: 1px;
+            height: 100%;
+            position: absolute;
+            left: 12px;
+            background-color: #00f5fe;
+          }
+        }
+      }
+    }
+  }
+
+  .input-box {
+    display: flex;
+    align-items: center;
+
+    .input-title {
+      color: #73e8fe;
+      width: auto;
+    }
+
+    margin-right: 10px;
+  }
+
+  .label {
+    max-width: 220px;
+  }
+
+  #fanLocalSelectDom {
+    :deep(.@{ventSpace}-select-dropdown) {
+      left: 0px !important;
+      top: 35px !important;
+    }
+  }
+
+  .@{ventSpace}-input {
+    width: 150px;
+  }
+
+  :deep(#LivePlayerBox) {
+    display: flex;
+    flex-direction: row;
+    justify-content: flex-end;
+    padding-right: 380px;
+    pointer-events: none;
+
+    .video-parent {
+      height: 208px;
+      pointer-events: auto !important;
+    }
+  }
+
+  .to-right {
+    :deep(#LivePlayerBox) {
+      padding-right: 0px;
+    }
+  }
+
+  :deep(.button-box) {
+    position: relative;
+    padding: 5px;
+    // border: 1px transparent solid;
+    border-radius: 5px;
+    margin-left: 8px;
+    margin-right: 8px;
+    width: auto;
+    // height: 40px;
+    // border: 1px solid #65dbea;
+    height: 35px !important;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    padding: 0 15px 5px 15px;
+    cursor: pointer;
+
+    &:hover {
+      background: linear-gradient(#2cd1ff55, #1eb0ff55);
+    }
+
+    &::before {
+      width: calc(100% - 6px);
+      height: 27px;
+      content: '';
+      position: absolute;
+      top: 3px;
+      right: 0;
+      left: 3px;
+      bottom: 0;
+      z-index: -1;
+      border-radius: inherit;
+      /*important*/
+      background: linear-gradient(#1fa6cb, #127cb5);
+    }
+
+    &::after {
+      width: calc(100% + 32px);
+      height: 10px;
+      content: '';
+      position: absolute;
+      top: 28px;
+      right: 0;
+      left: -16px;
+      bottom: 0;
+      z-index: -1;
+      border-radius: inherit;
+      /*important*/
+      background-position: center;
+      background-size: 100%;
+      z-index: 999;
+    }
+  }
+</style>

+ 5 - 23
src/views/vent/monitorManager/workFaceMonitor/wokeFace.threejs.ts

@@ -70,29 +70,11 @@ export const setModelType = (type, n = Math.ceil(Math.random() * 4), isShowPlane
       workFaceObj.setModalType(type);
       workFaceObj?.setPlanes(n);
       showOrHideGasPlane(isShowPlane);
-      if (type == 'workFace1') {
-        // 判断模型类型
-        var oldControlsPosition = { x: 0.055, y: 0.062, z: 0.117 };
-        var oldCameraPosition = { x: 0.055, y: 0.062, z: 0.117 };
-        var newCameraPosition = { x: -0.078, y: 2.524, z: 0.886 };
-        var newControlsPosition = { x: -0.078, y: 0.063, z: 0.181 };
-      } else if (type == 'workFace2') {
-        var oldControlsPosition = { x: 0.055, y: 0.062, z: 0.117 };
-        var oldCameraPosition = { x: 1.403, y: 3.354, z: 2.873 };
-        var newCameraPosition = { x: -0.078, y: 2.524, z: 0.886 };
-        var newControlsPosition = { x: -0.078, y: 0.063, z: 0.181 };
-      } else if (type == 'workFace3') {
-        // 双进单会
-        var oldControlsPosition = { x: 0.055, y: 0.062, z: 0.117 };
-        var oldCameraPosition = { x: 1.403, y: 3.354, z: 2.873 };
-        var newCameraPosition = { x: -0.0736339522439517, y: 2.8359333767190282, z: 1.1782304435986413 };
-        var newControlsPosition = { x: -0.0792833688241211, y: 0.1249789297357116, z: -0.07315650372945247 };
-      } else {
-        var oldControlsPosition = { x: 0.055, y: 0.062, z: 0.117 };
-        var oldCameraPosition = { x: 1.403, y: 3.354, z: 2.873 };
-        var newCameraPosition = { x: -0.17182200678070425, y: 1.7188311320712673, z: 1.787394450495768 };
-        var newControlsPosition = { x: -0.171622930063528, y: -0.1442344658741759, z: 0.032110784753260874 };
-      }
+      const oldControlsPosition = { x: 0.055, y: 0.062, z: 0.117 };
+      const oldCameraPosition = { x: 0.055, y: 0.062, z: 0.117 };
+      const newCameraPosition = { x: -1.6761668545944788, y: 26.453479850280285, z: 47.001334651484676 };
+      const newControlsPosition = { x: 0.021191, y: 0.077857, z: 0.069123 };
+
       if (model.scene.getObjectByName('workFace')) {
         model.camera.position.set(oldCameraPosition.x, oldCameraPosition.y, oldCameraPosition.z + 20);
         model.orbitControls.target.set(oldControlsPosition.x, oldControlsPosition.y, oldControlsPosition.z);

+ 5 - 2
src/views/vent/monitorManager/workFaceMonitor/workFace.threejs.base.ts

@@ -387,7 +387,10 @@ class WorkFace {
       // this.model.camera.position.set(0, 3.1, 500);
       // this.setRenderPass();
       this.model.orbitControls.update();
-      this.model.setGLTFModel(['workFace2-1', 'workFace1-1'], this.group).then(async () => {
+      this.model.setGLTFModel('workFace').then(async (gltf) => {
+        const gltfModal = gltf[0];
+        gltfModal.name = 'workFace';
+        this.group?.add(gltfModal);
         this.group.children.forEach((object: THREE.Object3D) => {
           if (object.name.startsWith('workFace')) {
             setModalCenter(object);
@@ -395,7 +398,7 @@ class WorkFace {
         });
         this.group.name = this.modelName;
 
-        // this.group.position.set(-0.06, 0.28, 0.07);
+        // this.group.position.set(-1.67, 26.45, 47.0);
         this.group.scale.set(2.5, 2.5, 2.5);
         // this.resetMesh();
         this.getPositions(this.glob.N);