瀏覽代碼

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

lxh 6 月之前
父節點
當前提交
27490020b2
共有 67 個文件被更改,包括 6402 次插入2740 次删除
  1. 3 3
      .env.development
  2. 二進制
      src/assets/images/themify/green/vent/border/box-bottom.png
  3. 二進制
      src/assets/images/themify/green/vent/border/box-top.png
  4. 二進制
      src/assets/images/themify/green/vent/sheet-bg.png
  5. 二進制
      src/assets/images/themify/green/vent/sheet-header.png
  6. 二進制
      src/assets/images/themify/green/vent/vent-header1.png
  7. 6 0
      src/components/vent/customHeader.vue
  8. 40 28
      src/components/vent/ventBox1.vue
  9. 2 0
      src/design/theme.less
  10. 68 0
      src/design/themify/green.less
  11. 1 0
      src/enums/appEnum.ts
  12. 45 27
      src/hooks/vent/useSvgAnimation.ts
  13. 4 0
      src/layouts/default/header/components/user-dropdown/ThemeSelect.vue
  14. 1 1
      src/store/constant.ts
  15. 22 5
      src/utils/http/axios/index.ts
  16. 144 129
      src/views/monitor/quartz/index.vue
  17. 33 0
      src/views/monitor/quartz/quartz.api.ts
  18. 9 0
      src/views/monitor/quartz/quartz.data.ts
  19. 1 0
      src/views/system/user/user.data.ts
  20. 2 0
      src/views/vent/comment/threejs/ArrowFlow.ts
  21. 10 7
      src/views/vent/comment/threejs/SmokePartical.ts
  22. 23 61
      src/views/vent/dataCenter/deviceCenter/device.api.ts
  23. 205 101
      src/views/vent/dataCenter/deviceCenter/index.vue
  24. 70 15
      src/views/vent/dataCenter/infoCenter/index.vue
  25. 26 0
      src/views/vent/dataCenter/infoCenter/infoCenter.api.ts
  26. 59 93
      src/views/vent/dataCenter/infoCenter/infoCenter.data.ts
  27. 9 62
      src/views/vent/dataCenter/stationCenter/device.api.ts
  28. 928 100
      src/views/vent/dataCenter/stationCenter/index.vue
  29. 3 3
      src/views/vent/gas/gasReport/gas-report.api.ts
  30. 486 454
      src/views/vent/gas/gasReport/index.vue
  31. 1 1
      src/views/vent/home/clique/components/3Dmap/3dMap.ts
  32. 81 71
      src/views/vent/home/configurable/components/ModuleCommon.vue
  33. 20 10
      src/views/vent/home/configurable/components/ModuleCommonDual.vue
  34. 62 41
      src/views/vent/home/configurable/configurable.api.ts
  35. 5 1
      src/views/vent/home/configurable/dust.vue
  36. 5 0
      src/views/vent/home/configurable/fire.vue
  37. 8 7
      src/views/vent/home/configurable/ventSDG.vue
  38. 33 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.data.ts
  39. 351 0
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressHomeSP.vue
  40. 250 0
      src/views/vent/monitorManager/balancePressMonitor/indexSP.vue
  41. 15 116
      src/views/vent/monitorManager/comment/GroupMonitorTable.vue
  42. 6 1
      src/views/vent/monitorManager/deviceMonitor/staticSheets/commonSheet.vue
  43. 6 1
      src/views/vent/monitorManager/deviceMonitor/staticSheets/dustSheet.vue
  44. 6 1
      src/views/vent/monitorManager/deviceMonitor/staticSheets/fireSheet.vue
  45. 6 1
      src/views/vent/monitorManager/deviceMonitor/staticSheets/gasSheet.vue
  46. 6 1
      src/views/vent/monitorManager/deviceMonitor/staticSheets/ventilateSheet.vue
  47. 400 0
      src/views/vent/monitorManager/fanLocalMonitor/fanLocal.threejs.single.ts
  48. 56 37
      src/views/vent/monitorManager/fanLocalMonitor/fanLocal.threejs.ts
  49. 16 7
      src/views/vent/monitorManager/fanLocalMonitor/index.vue
  50. 174 0
      src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.fire.redGate.ts
  51. 7 0
      src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.fire.ts
  52. 7 0
      src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.fireF.ts
  53. 230 0
      src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ssl.ts
  54. 151 74
      src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ts
  55. 299 296
      src/views/vent/monitorManager/fireDoorMonitor/index.vue
  56. 12 12
      src/views/vent/monitorManager/gateMonitor/gate.threejs.ts
  57. 249 0
      src/views/vent/monitorManager/mainFanMonitor/components/entryThree.vue
  58. 699 0
      src/views/vent/monitorManager/mainFanMonitor/components/mainFanSVG.vue
  59. 20 236
      src/views/vent/monitorManager/mainFanMonitor/index.vue
  60. 25 2
      src/views/vent/monitorManager/mainFanMonitor/main.data.ts
  61. 45 1
      src/views/vent/monitorManager/mainFanMonitor/main.threejs.ts
  62. 199 0
      src/views/vent/monitorManager/mainFanMonitor/mainWind.lidt.threejs.ts
  63. 11 4
      src/views/vent/monitorManager/windowMonitor/components/windowDualSVG.vue
  64. 3 1
      src/views/vent/monitorManager/windowMonitor/components/windowSVG.vue
  65. 725 729
      src/views/vent/monitorManager/windrectMonitor/index.vue
  66. 9 0
      src/views/vent/sys/setting/index.vue
  67. 4 0
      src/views/vent/sys/setting/setting.data.ts

+ 3 - 3
.env.development

@@ -6,7 +6,7 @@ VITE_PUBLIC_PATH = /
 
 # 跨域代理,您可以配置多个 ,请注意,没有换行符
 #VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
-VITE_PROXY = [["/sw","http://182.92.126.35:6008"],["/jeecgsystem","http://182.92.126.35:9999"],["/upload","http://182.92.126.35:9999/upload"],["/documents", "http://182.92.126.35:9050"],["/modelreq", "http://182.92.126.35:9999"],["/webRtc", "http://182.92.126.35:8051"], ["/python", "http://127.0.0.1:8008"], ["/tun2D", "http://127.0.0.1:8088/micro-vent-2dModal/tun2D"]]
+VITE_PROXY = [["/sw","http://182.92.126.35:6008"],["/jeecgsystem","http://182.92.126.35:9999"],["/upload","http://182.92.126.35:9999/upload"],["/documents", "http://182.92.126.35:9050"],["/modelreq", "http://182.92.126.35:9999"],["/webRtc", "http://182.92.126.35:8051"], ["/python", "http://127.0.0.1:8008"], ["/tun2D", "http://127.0.0.1:8088/micro-vent-2dModal/tun2D"],["/dataCenter", "http://192.168.1.88:10999"],["/sjzx", "http://192.168.1.88:8062/"]]
 # VITE_PROXY = [["/jeecgsystem","http://192.168.183.88:9999"],["/upload","http://192.168.183.88:9999/upload"],["/documents", "http://192.168.183.88:9050"],["/modelreq", "http://192.168.183.88:9999"],["/webRtc", "http://192.168.183.88:8051"]]
 # VITE_PROXY = [["/jeecgsystem","http://10.10.150.72:9999"],["/upload","http://localhost:3300/upload"],["/documents", "http://10.10.150.72:9050"],["/modelreq", "http://10.10.150.72:9999"],["/webRtc", "http://192.168.183.216:8051"]]
 # VITE_PROXY = [["/jeecgsystem","http://192.168.1.8:9999"],["/upload","http://localhost:3300/upload"]]
@@ -29,7 +29,7 @@ VITE_GLOB_API_URL_PREFIX=
 
 #微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
 #VITE_APP_SUB_APP = [["micro-need-air", "//10.10.150.72:8099/"], ["micro-vent-3dModal", "//localhost:8091/"], ["micro-fire-front", "//localhost:8090/"]]
-# VITE_APP_SUB_APP = [["micro-vent-3dModal", "//192.168.183.88:8091/", "micro-vent-3dModal"], ["micro-need-air", "//192.168.183.88:8093/", "micro-need-air"], ["micro-fire-front", "//localhost:8097/", "fire-Micro"]]
 # VITE_APP_SUB_APP = [["micro-vent-3dModal", "//192.168.183.154:8091/", "micro-vent-3dModal"], ["micro-need-air", "//192.168.183.88:8093/", "micro-need-air"], ["micro-fire-front", "//localhost:8097/", "fire-Micro"]]
-VITE_APP_SUB_APP = [["micro-vent-3dModal", "//182.92.126.35:8091/", "micro-vent-3dModal"],["micro-vent-2dModal", "//localhost:8088/", "micro-vent-2dModal"],["micro-vent-doc", "//localhost:5173/", "micro-vent-doc"],["micro-need-air", "//182.92.126.35:8093/", "micro-need-air"], ["micro-fire-front", "//182.92.126.35:8097/", "fire-Micro"]]
+VITE_APP_SUB_APP = [["micro-vent-3dModal", "//192.168.1.16:8091/", "micro-vent-3dModal"], ["micro-need-air", "//192.168.183.88:8093/", "micro-need-air"], ["micro-fire-front", "//localhost:8097/", "fire-Micro"]]
+# VITE_APP_SUB_APP = [["micro-vent-3dModal", "//182.92.126.35:8091/", "micro-vent-3dModal"],["micro-vent-2dModal", "//localhost:8088/", "micro-vent-2dModal"],["micro-vent-doc", "//localhost:5173/", "micro-vent-doc"],["micro-need-air", "//182.92.126.35:8093/", "micro-need-air"], ["micro-fire-front", "//182.92.126.35:8097/", "fire-Micro"]]
 # VITE_APP_SUB_APP = [["micro-vent-3dModal", "//localhost:8091/"], ["micro-need-air", "//localhost:8099/"], ["micro-fire-front", "//localhost:8090/"]]

二進制
src/assets/images/themify/green/vent/border/box-bottom.png


二進制
src/assets/images/themify/green/vent/border/box-top.png


二進制
src/assets/images/themify/green/vent/sheet-bg.png


二進制
src/assets/images/themify/green/vent/sheet-header.png


二進制
src/assets/images/themify/green/vent/vent-header1.png


+ 6 - 0
src/components/vent/customHeader.vue

@@ -85,6 +85,12 @@
   @import '/@/design/theme.less';
   @ventSpace: zxm;
 
+  @{theme-green} {
+    .vent-custom-header {
+      --image-vent-header1: url('/@/assets/images/themify/green/vent/vent-header1.png');
+      --image-select-bg: url('/@/assets/images/themify/deepblue/vent/home/select-bg.png');
+    }
+  }
   @{theme-deepblue} {
     .vent-custom-header {
       --image-vent-header1: url('/@/assets/images/themify/deepblue/vent/vent-header1.png');

+ 40 - 28
src/components/vent/ventBox1.vue

@@ -23,38 +23,50 @@
 
 <style lang="less" scoped>
   @import '/@/design/theme.less';
-
-  @{theme-deepblue} {
+  @{theme-green} {
     .vent-box1-bg {
-      --image-box1-top: url('/@/assets/images/themify/deepblue/vent/border/box2-top.png');
-      --image-box1-bottom: none;
-      // --image-box1-bottom: url('/@/assets/images/themify/deepblue/vent/border/box1-bottom.png');
-      --container-color: #0e223b;
-      // --container-image: linear-gradient(#3df6ff00, #2c3f59, #3df6ff00);
-      --container-image: none;
+      --image-box1-top: url(/@/assets/images/themify/green/vent/border/box-top.png);
+      --image-box1-bottom: url('/@/assets/images/themify/green/vent/border/box-bottom.png');
+      // --container-color: #1e2932;
+      --container-image: linear-gradient(#3df6ff00, #308972, #3df6ff00);
     }
+    // .box1-center {
+    //   height: calc(100% - 37px);
+    //   clip-path: polygon(0 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 10px 100%, 0 calc(100% - 10px));
+    // }
+  }
 
-    .vent-box1-bg {
-      border: 1px solid #3a4b5f;
-      border-radius: 10px;
-      background: var(--container-color) no-repeat;
-      padding-top: 5px;
+  // @{theme-deepblue} {
+  //   .vent-box1-bg {
+  //     --image-box1-top: url('/@/assets/images/themify/deepblue/vent/border/box2-top.png');
+  //     --image-box1-bottom: none;
+  //     // --image-box1-bottom: url('/@/assets/images/themify/deepblue/vent/border/box1-bottom.png');
+  //     --container-color: #0e223b;
+  //     // --container-image: linear-gradient(#3df6ff00, #2c3f59, #3df6ff00);
+  //     --container-image: none;
+  //   }
 
-      .box1-top {
-        height: 35px;
-        background: var(--image-box1-top) no-repeat;
-        background-size: 94% 25px;
-        background-position: center center;
-        margin-bottom: 5px;
-        .title {
-          height: 100%;
-          padding-left: 8%;
-          justify-content: flex-start;
-          align-items: center;
-        }
-      }
-    }
-  }
+  //   .vent-box1-bg {
+  //     border: 1px solid #3a4b5f;
+  //     border-radius: 10px;
+  //     background: var(--container-color) no-repeat;
+  //     padding-top: 5px;
+
+  //     .box1-top {
+  //       height: 35px;
+  //       background: var(--image-box1-top) no-repeat;
+  //       background-size: 94% 25px;
+  //       background-position: center center;
+  //       margin-bottom: 5px;
+  //       .title {
+  //         height: 100%;
+  //         padding-left: 8%;
+  //         justify-content: flex-start;
+  //         align-items: center;
+  //       }
+  //     }
+  //   }
+  // }
 
   .vent-box1-bg {
     --image-box1-top: url('/@/assets/images/vent/border/box1-top.png');

+ 2 - 0
src/design/theme.less

@@ -2,6 +2,7 @@
 @import './themify/light.less';
 @import './themify/default.less';
 @import './themify/deepblue.less';
+@import './themify/green.less';
 
 @ventSpace: zxm;
 
@@ -138,3 +139,4 @@ html[data-theme='light'] {
 @theme-light: ~"html[data-theme='light']";
 @theme-default: ~'html';
 @theme-deepblue: ~"html[data-theme='deepblue']";
+@theme-green: ~"html[data-theme='green']";

+ 68 - 0
src/design/themify/green.less

@@ -0,0 +1,68 @@
+html[data-theme='green'] {
+  --vent-primary-color: #0a84ff;
+
+  --vent-header-bg-color: linear-gradient(#0a84ff99, #0a84ff22);
+
+  --vent-btn-primary-hover-color: #2986e9;
+  --vent-btn-primary-focus-color: #4cc4b5;
+  --vent-btn-primary-color: #257180;
+  --vent-btn-primary-border-color: #3f506a;
+
+  --vent-table-thead: #172943;
+  --vent-table-thead-border: #4cc4b5;
+  --vent-table-hover: #2c4650;
+  --vent-table-no-hover: #223038;
+  --vent-table-action-link: #86b9a7;
+
+  --vent-modal-title: #0a80fa;
+  --vent-modal-border: #308972;
+  --vent-modal-bg: #181b24;
+  --vent-modal-box-shadow: #316b92;
+  --vent-modal-bg2: linear-gradient(#2986e955, #0963c155);
+
+  --vent-tabs-bg: linear-gradient(#0091aa33, #2081ff11);
+  --vent-tabs-table-thead: #3d9dd433;
+  // --vent-tabs-action-link: #28f3f3;
+  // --vent-tabs-bg: linear-gradient(#28385155, #27334722);
+  // --vent-tabs-table-thead: #172943;
+  --vent-tabs-action-link: #0a80fa;
+
+  --vent-form-item-border: #308972;
+
+  --vent-text-base: #fff;
+  --vent-base-color: #181b24;
+  --vent-base-border: #3f506a;
+  --vent-base-light-bg: #8691a3;
+  --vent-base-light-bg-opcity: #8691a355;
+  --vent-transparent: #1e2932;
+  --vent-font-color: #ffffff;
+  --vent-font-action-link: #0a80fa;
+
+  --vent-configurable-bg: #02132c;
+  --vent-configurable-module-bg: #0d2037;
+  --vent-configurable-original-module-bg: #0d203711;
+  --vent-configurable-module-border-bd: linear-gradient(#3b4c65 0%, #3b4c65 60%, #000723);
+  --vent-configurable-dropdown: linear-gradient(to bottom, #293645, #3b4550);
+  --vent-configurable-home-bg-img: linear-gradient(to top, #39a3ff00, #0091ff99);
+  --vent-configurable-home-timeline: linear-gradient(to top, #39a3ff00, #0091ff99, #39a3ff00);
+  --vent-configurable-home-light-border: #fbfdff;
+
+  --vent-gas-list-item-bg-img: linear-gradient(to right, #213248, #21324800);
+  --vent-gas-tab-bg: #10427a;
+  --vent-gas-tab-bg-actived: #166ab5;
+  --vent-gas-tab-border: #525c68;
+  --vent-gas-primary-text: #ededed;
+  --vent-gas-primary-bg: #244d84;
+  --vent-gas-primary-trasparent-bg: #0091ff12;
+
+  --vent-device-manager-box-border: #fff;
+  --vent-device-manager-box-bg: #aaaaaa11;
+  --vent-device-manager-control-btn: linear-gradient(#1572d5, #0963c1);
+  --vent-device-manager-control-btn-hover: linear-gradient(#1572d555, #0963c155);
+
+  --vent-warn-tab-bg: #0f376c;
+  --vent-warn-tab-border: #107eec;
+  --vent-warn-tab-bg-actived: #0963c1;
+
+
+}

+ 1 - 0
src/enums/appEnum.ts

@@ -24,6 +24,7 @@ export enum ThemeEnum {
   LIGHT = 'light',
   VENT1 = 'vent1',
   DEEPBLUE = 'deepblue',
+  GREEN = 'green',
 }
 
 export enum SettingButtonPositionEnum {

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

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

+ 4 - 0
src/layouts/default/header/components/user-dropdown/ThemeSelect.vue

@@ -45,6 +45,10 @@
       value: ThemeEnum.DEEPBLUE,
       label: '深蓝',
     },
+    {
+      value: ThemeEnum.GREEN,
+      label: '绿色',
+    },
   ];
 
   const { getDarkMode, setDarkMode } = useRootSetting();

+ 1 - 1
src/store/constant.ts

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

+ 22 - 5
src/utils/http/axios/index.ts

@@ -18,9 +18,14 @@ import { useErrorLogStoreWithOut } from '/@/store/modules/errorLog';
 import { useI18n } from '/@/hooks/web/useI18n';
 import { joinTimestamp, formatRequestDate } from './helper';
 import { useUserStoreWithOut } from '/@/store/modules/user';
+
 const globSetting = useGlobSetting();
 const urlPrefix = globSetting.urlPrefix;
 const { createMessage, createErrorModal } = useMessage();
+debugger;
+const proxyFixList = JSON.parse(import.meta.env.VITE_PROXY + '').map((item) => {
+  return item[0].replace(/\//g, '');
+});
 
 /**
  * @description: 数据处理,方便区分多种处理方式
@@ -110,11 +115,18 @@ const transform: AxiosTransform = {
         config.url = `${urlPrefix}${config.url}`;
       }
       if (apiUrl && isString(apiUrl)) {
-        if (config.url?.startsWith('/gasServerImg')) {
-          config.url = `/sw${config.url}`;
-        } else {
+        const firstCode = config.url?.split('/')[1];
+        const currentPort = window.location.port;
+        if (currentPort === '8062' && !proxyFixList.includes(firstCode)) {
+          config.url = `/dataCenter${config.url}`;
+        } else if (!proxyFixList || !proxyFixList.includes(firstCode)) {
           config.url = `${apiUrl}${config.url}`;
         }
+        // if (config.url?.startsWith('/gasServerImg')) {
+        //   config.url = `/sw${config.url}`;
+        // } else {
+        //   config.url = `${apiUrl}${config.url}`;
+        // }
       }
       const params = config.params || {};
       const data = config.data || false;
@@ -188,8 +200,13 @@ const transform: AxiosTransform = {
    * @description: 请求拦截器处理
    */
   requestInterceptors: (config: Recordable, options) => {
-    // 请求之前处理config
-    const token = getToken();
+    let token: string | null = null;
+    if (config.headers['X-Access-Token']) {
+      config.headers.Authorization = config.headers['X-Access-Token'];
+      token = config.headers['X-Access-Token'];
+    } else {
+      token = getToken();
+    }
     let tenantId: string | number = getTenantId();
     if (token && (config as Recordable)?.requestOptions?.withToken !== false) {
       // jwt token

+ 144 - 129
src/views/monitor/quartz/index.vue

@@ -36,150 +36,165 @@
   </div>
 </template>
 <script lang="ts" name="monitor-quartz" setup>
-  import { ref } from 'vue';
-  import { BasicTable, TableAction } from '/@/components/Table';
-  import { useModal } from '/@/components/Modal';
-  import { useListPage } from '/@/hooks/system/useListPage';
-  import { getQuartzList, deleteQuartz, batchDeleteQuartz, executeImmediately, resumeJob, pauseJob, getExportUrl, getImportUrl } from './quartz.api';
-  import { columns, searchFormSchema } from './quartz.data';
-  import QuartzModal from './QuartzModal.vue';
-  import { useMessage } from '/@/hooks/web/useMessage';
+import { ref } from 'vue';
+import { BasicTable, TableAction } from '/@/components/Table';
+import { useModal } from '/@/components/Modal';
+import { useListPage } from '/@/hooks/system/useListPage';
+import {
+  getQuartzList,
+  deleteQuartz,
+  batchDeleteQuartz,
+  executeImmediately,
+  resumeJob,
+  pauseJob,
+  getExportUrl,
+  getImportUrl,
+  collectJob,
+  monitorJob,
+  computeJob,
+} from './quartz.api';
+import { columns, searchFormSchema } from './quartz.data';
+import QuartzModal from './QuartzModal.vue';
+import { useMessage } from '/@/hooks/web/useMessage';
 
-  const { createMessage } = useMessage();
-  const [registerModal, { openModal }] = useModal();
-  // 列表页面公共参数、方法
-  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
-    designScope: 'quartz-template',
-    tableProps: {
-      title: '任务列表',
-      api: getQuartzList,
-      columns: columns,
-      actionColumn: {
-        width: 180,
-      },
-      formConfig: {
-        labelWidth: 120,
-        schemas: searchFormSchema,
-        fieldMapToTime: [['fieldTime', ['beginDate', 'endDate'], 'YYYY-MM-DD HH:mm:ss']],
-      },
+const { createMessage } = useMessage();
+const [registerModal, { openModal }] = useModal();
+// 列表页面公共参数、方法
+const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
+  designScope: 'quartz-template',
+  tableProps: {
+    title: '任务列表',
+    api: getQuartzList,
+    columns: columns,
+    actionColumn: {
+      width: 180,
     },
-    exportConfig: {
-      name: '定时任务列表',
-      url: getExportUrl,
+    formConfig: {
+      labelWidth: 120,
+      schemas: searchFormSchema,
+      fieldMapToTime: [['fieldTime', ['beginDate', 'endDate'], 'YYYY-MM-DD HH:mm:ss']],
     },
-    importConfig: {
-      url: getImportUrl,
-    },
-  });
+  },
+  exportConfig: {
+    name: '定时任务列表',
+    url: getExportUrl,
+  },
+  importConfig: {
+    url: getImportUrl,
+  },
+});
 
-  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
 
-  /**
-   * 操作列定义
-   * @param record
-   */
-  function getActions(record) {
-    return [
-      {
-        label: '启动',
-        popConfirm: {
-          title: '是否启动选中任务?',
-          confirm: handlerResume.bind(null, record),
-        },
-        ifShow: (_action) => {
-          return record.status == -1;
-        },
+/**
+ * 操作列定义
+ * @param record
+ */
+function getActions(record) {
+  return [
+    {
+      label: '启动',
+      popConfirm: {
+        title: '是否启动选中任务?',
+        confirm: handlerResume.bind(null, record),
       },
-      {
-        label: '停止',
-        popConfirm: {
-          title: '是否暂停选中任务?',
-          confirm: handlerPause.bind(null, record),
-        },
-        ifShow: (_action) => {
-          return record.status == 0;
-        },
+      ifShow: (_action) => {
+        return record.status == -1;
       },
-    ];
-  }
-
-  /**
-   * 下拉操作栏
-   */
-  function getDropDownAction(record) {
-    return [
-      {
-        label: '立即执行',
-        popConfirm: {
-          title: '是否立即执行任务?',
-          confirm: handlerExecute.bind(null, record),
-        },
+    },
+    {
+      label: '停止',
+      popConfirm: {
+        title: '是否暂停选中任务?',
+        confirm: handlerPause.bind(null, record),
+      },
+      ifShow: (_action) => {
+        return record.status == 0;
       },
-      {
-        label: '编辑',
-        onClick: handleEdit.bind(null, record),
+    },
+  ];
+}
+
+/**
+ * 下拉操作栏
+ */
+function getDropDownAction(record) {
+  return [
+    {
+      label: '立即执行',
+      popConfirm: {
+        title: '是否立即执行任务?',
+        confirm: handlerExecute.bind(null, record),
       },
-      {
-        label: '删除',
-        popConfirm: {
-          title: '是否确认删除',
-          confirm: handleDelete.bind(null, record),
-        },
+    },
+    {
+      label: '编辑',
+      onClick: handleEdit.bind(null, record),
+    },
+    {
+      label: '删除',
+      popConfirm: {
+        title: '是否确认删除',
+        confirm: handleDelete.bind(null, record),
       },
-    ];
-  }
+    },
+  ];
+}
 
-  /**
-   * 新增事件
-   */
-  function handleAdd() {
-    openModal(true, {
-      isUpdate: false,
-    });
-  }
+/**
+ * 新增事件
+ */
+function handleAdd() {
+  openModal(true, {
+    isUpdate: false,
+  });
+}
 
-  /**
-   * 编辑事件
-   */
-  function handleEdit(record) {
-    openModal(true, {
-      record,
-      isUpdate: true,
-    });
-  }
+/**
+ * 编辑事件
+ */
+function handleEdit(record) {
+  openModal(true, {
+    record,
+    isUpdate: true,
+  });
+}
 
-  /**
-   * 删除事件
-   */
-  async function handleDelete(record) {
-    await deleteQuartz({ id: record.id }, reload);
-  }
+/**
+ * 删除事件
+ */
+async function handleDelete(record) {
+  await deleteQuartz({ id: record.id }, reload);
+}
 
-  /**
-   * 立即执行
-   */
-  async function handlerExecute(record) {
-    await executeImmediately({ id: record.id }, reload);
-  }
+/**
+ * 立即执行
+ */
+async function handlerExecute(record) {
+  await executeImmediately({ id: record.id }, reload);
+}
 
-  /**
-   * 暂停
-   */
-  async function handlerPause(record) {
-    await pauseJob({ id: record.id }, reload);
-  }
+/**
+ * 暂停
+ */
+async function handlerPause(record) {
+  await pauseJob({ id: record.id }, reload);
+}
 
-  /**
-   * 启动
-   */
-  async function handlerResume(record) {
-    await resumeJob({ id: record.id }, reload);
-  }
+/**
+ * 启动
+ */
+async function handlerResume(record) {
+  // if (record.ntype === 'dataCenter') {
+  console.log(record.ntype, '类型');
+  // await collectJob({ id: record.id }, reload);
+  // } else await resumeJob({ id: record.id }, reload);
+}
 
-  /**
-   * 批量删除事件
-   */
-  async function batchHandleDelete() {
-    await batchDeleteQuartz({ ids: selectedRowKeys.value }, reload);
-  }
+/**
+ * 批量删除事件
+ */
+async function batchHandleDelete() {
+  await batchDeleteQuartz({ ids: selectedRowKeys.value }, reload);
+}
 </script>

+ 33 - 0
src/views/monitor/quartz/quartz.api.ts

@@ -13,6 +13,10 @@ enum Api {
   importExcelUrl = '/ventanaly/quartzJob/importExcel',
   execute = '/ventanaly/quartzJob/execute',
   deleteBatch = '/ventanaly/quartzJob/deleteBatch',
+  //数据中心  启动  停止   立即执行接口
+  collect = '/collect/quartzJob',
+  compute = '/compute/quartzJob',
+  monitor = '/ventanaly/quartzJob',
 }
 
 /**
@@ -88,6 +92,35 @@ export const executeImmediately = (params, handleSuccess) => {
   });
 };
 
+/**
+ * 数据中心---启动
+ * @param params
+ */
+export const collectJob = (params, handleSuccess) => {
+  return defHttp.get({ url: Api.collect, params }).then(() => {
+    handleSuccess();
+  });
+};
+
+/**
+ * 数据中心---暂停
+ * @param params
+ */
+export const computeJob = (params, handleSuccess) => {
+  return defHttp.get({ url: Api.compute, params }).then(() => {
+    handleSuccess();
+  });
+};
+
+/**
+ * 数据中心---立即执行
+ * @param params
+ */
+export const monitorJob = (params, handleSuccess) => {
+  return defHttp.get({ url: Api.monitor, params }).then(() => {
+    handleSuccess();
+  });
+};
 /**
  * 批量删除任务
  * @param params

+ 9 - 0
src/views/monitor/quartz/quartz.data.ts

@@ -67,6 +67,15 @@ export const formSchema: FormSchema[] = [
     component: 'Input',
     required: true,
   },
+  {
+    label: '系统类型',
+    field: 'jobSysType',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'jobSysType',
+      placeholder: '请选择系统类型',
+    },
+  },
   {
     field: 'cronExpression',
     label: 'Cron表达式',

+ 1 - 0
src/views/system/user/user.data.ts

@@ -211,6 +211,7 @@ export const formSchema: FormSchema[] = [
     label: '所属部门',
     field: 'selecteddeparts',
     component: 'JSelectDept',
+    required: true,
     componentProps: ({ formActionType, formModel }) => {
       return {
         sync: false,

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

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

+ 10 - 7
src/views/vent/comment/threejs/SmokePartical.ts

@@ -70,26 +70,29 @@ export default class SmokePartical {
               (Math.random() * 2 - 1) * 3 + obj.path1.z
             );
           } else {
+            const len = obj.spreadRang ? obj.spreadRang : 3;
             vec = new THREE.Vector3(
-              (Math.random() * 2 - 1) * 3 + obj.path1.x,
-              (Math.random() * 2 - 1) * 3 + obj.path1.y,
-              (Math.random() * 2 - 1) * 3 + obj.path1.z
+              (Math.random() * 2 - 1) * len + obj.path1.x,
+              (Math.random() * 2 - 1) * len + obj.path1.y,
+              (Math.random() * 2 - 1) * len + obj.path1.z
             );
           }
           obj.path1.copy(vec);
         } else if (obj.spreadDirection == -1) {
           let vec;
           if (Math.abs(obj.path0.y - obj.path1.y) > 3) {
+            const len = obj.spreadRang ? obj.spreadRang : 8;
             vec = new THREE.Vector3(
               (Math.random() * 2 - 1) * 3 + obj.path0.x,
-              Math.random() * 8 + obj.path0.y,
+              Math.random() * len + obj.path0.y,
               (Math.random() * 2 - 1) * 3 + obj.path0.z
             );
           } else {
+            const len = obj.spreadRang ? obj.spreadRang : 3;
             vec = new THREE.Vector3(
-              (Math.random() * 2 - 1) * 3 + obj.path0.x,
-              (Math.random() * 2 - 1) * 3 + obj.path0.y,
-              (Math.random() * 2 - 1) * 3 + obj.path0.z
+              (Math.random() * 2 - 1) * len + obj.path0.x,
+              (Math.random() * 2 - 1) * len + obj.path0.y,
+              (Math.random() * 2 - 1) * len + obj.path0.z
             );
           }
           obj.path0.copy(vec);

+ 23 - 61
src/views/vent/dataCenter/deviceCenter/device.api.ts

@@ -1,67 +1,29 @@
 import { defHttp } from '/@/utils/http/axios';
 
 enum Api {
-  list = '/monitor/device',
-  baseList = '/safety/ventanalyDeviceInfo/list',
-  // deviceTypeList = '/safety/ventanalyDeviceInfo/DeviceKind/query',
-  // deviceTypeList = '/sys/dict/DeviceKind/queryBySystem',
   deviceTypeList = '/safety/ventanalyDeviceInfo/DeviceKind/queryBySystem',
-  itemList = '/sys/dictItem/list',
-  devPosition = '/sys/dict/getDictItems/devPosVisible',
-  getDepartmentInfo = '/monitor/getDepartmentInfo',
-  listdays = '/safety/ventanalyMonitorData/listdays',
-  getHistoryData = '/monitor/history/getHistoryData',
-  safetyDeviceList = '/monitor/codeDict',
-  exportXlsUrl = '/monitor/exportXls',
-  queryNowGasInsInfo = '/safety/gasDayReport/queryNowGasInsInfo', //查询当前各班瓦斯巡检信息
-  queryNowGasSta = '/safety/gasDayReport/queryNowGasSta',
-  queryReportData = '/safety/reportLocalData/queryReportData', //查询瓦斯日报列表
-  getDeviceListBySubId = '/safety/ventanalyDeviceInfo/getDeviceListBySubId', //查询分站
-  getDeviceHistoryData = '/safety/ventanalyMonitorData/getRealHistoryData', //查询设备历史数据
-  getRegulation = '/monitor/getDeviceRegulation',
+  deviceList = '/dataCenter/compute/deviceData/getDeviceAll',
+  devMonitorList = '/dataCenter/compute/deviceData/getDeviceMonitorInfo',
 }
-//分站全部列表
-export const getListAll = () => defHttp.post({ url: Api.getDeviceListBySubId });
-/**
- * 列表接口
- * @param params
- */
-export const list = (params) => defHttp.post({ url: Api.list, params });
-
-/**
- * 保存或者更新用户
- * @param params
- */
-export const getDeviceList = (params) => defHttp.get({ url: Api.baseList, params });
-
 export const getDeviceTypeList = (params) => defHttp.get({ url: Api.deviceTypeList, params });
-
-export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
-export const devPosition = (params) => defHttp.get({ url: Api.devPosition, params });
-
-export const getDepartmentInfo = (params) => defHttp.get({ url: Api.getDepartmentInfo, params });
-
-export const listdays = (params) => defHttp.get({ url: Api.listdays, params });
-export const getHistoryData = (params) => defHttp.post({ url: Api.getHistoryData, params });
-export const safetyDeviceList = (params) => defHttp.post({ url: Api.safetyDeviceList, params });
-export const queryNowGasInsInfo = (params) => defHttp.post({ url: Api.queryNowGasInsInfo, params });
-
-export const getExportUrl = Api.exportXlsUrl;
-/**
- * 列表接口
- * @param params
- */
-export const queryNowGasSta = (params) => defHttp.post({ url: Api.queryNowGasSta, params });
-/**
- * 瓦斯日报列表
- * @param params
- */
-export const queryReportData = (params) => defHttp.post({ url: Api.queryReportData, params });
-
-/**
- * 设备历史数据接口
- * @param params
- */
-export const getDeviceHistoryData = (params) => defHttp.post({ url: Api.getDeviceHistoryData, data: params });
-
-export const getRegulation = (params) => defHttp.post({ url: Api.getRegulation, params });
+//根据设备类型获取设备列表
+// export const getDeviceListByType = (params) => defHttp.post({ url: Api.deviceList, params });
+export const getDeviceListByType = (params) =>
+  defHttp.post({
+    headers: {
+      'X-Access-Token':
+        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzU5ODQxMTcwfQ.fHaM3l-d88tUSLOs8sstXsDuSCn6Agbj_EMZMgV6waw',
+    },
+    url: Api.deviceList,
+    params,
+  });
+//根据设备id获取设备监控数据
+export const getDevMonitorListById = (params) =>
+  defHttp.post({
+    headers: {
+      'X-Access-Token':
+        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzU5ODQxMTcwfQ.fHaM3l-d88tUSLOs8sstXsDuSCn6Agbj_EMZMgV6waw',
+    },
+    url: Api.devMonitorList,
+    params,
+  });

+ 205 - 101
src/views/vent/dataCenter/deviceCenter/index.vue

@@ -4,6 +4,7 @@
     <div class="content">
       <a-tabs class="tab-box" v-model:activeKey="activeKey" @change="onChangeTab">
         <a-tab-pane tab="设备监测" key="device" />
+        <a-tab-pane tab="历史数据" key="history" />
       </a-tabs>
       <div class="box-content">
         <!-- 分站监测 -->
@@ -23,8 +24,8 @@
               </div>
             </div>
           </div>
-          <div class="right-box">
-            <div class="right-title">详细信息:</div>
+          <div class="right-box" v-if="activeKey == 'device'">
+            <div class="right-title">实时监测:</div>
             <a-table
               size="small"
               :scroll="{ y: 680 }"
@@ -58,14 +59,15 @@
                 <a-table
                   size="small"
                   :columns="innerColumns"
-                  :data-source="record.monitoringFields"
-                  :pagination="false"
+                  :data-source="monitorList"
+                  :pagination="pagination"
                   :loading="loadingMap[record.id]"
                   bordered
+                  overflow-y="auto"
                 >
                   <template #bodyCell="{ column, record: innerRecord }">
                     <template v-if="column.dataIndex === 'value'">
-                      <span :class="getValueClass(innerRecord.value)">
+                      <span>
                         {{ innerRecord.value }}
                       </span>
                     </template>
@@ -74,6 +76,10 @@
               </template>
             </a-table>
           </div>
+          <div class="right-box" v-else-if="activeKey == 'history'">
+            <div class="right-title">历史数据:</div>
+            <a-table></a-table>
+          </div>
         </div>
       </div>
     </div>
@@ -81,26 +87,160 @@
 </template>
 
 <script setup lang="ts">
-import { ref, nextTick, reactive, onMounted, onUnmounted, inject } from 'vue';
+import { ref, nextTick, reactive, onMounted, onUnmounted, inject, shallowRef, computed } from 'vue';
 import { usePermission } from '/@/hooks/web/usePermission';
 import customHeader from '/@/components/vent/customHeader.vue';
 import { AesEncryption } from '/@/utils/cipher';
 import { loginCipher } from '/@/settings/encryptionSetting';
 import { message, TreeProps } from 'ant-design-vue';
-import { list, getDeviceList, getDeviceTypeList, devPosition, getDepartmentInfo, getExportUrl, getRegulation } from './device.api';
+import { getDeviceTypeList, getDeviceListByType, getDevMonitorListById } from './device.api';
 import { DownOutlined, RightOutlined } from '@ant-design/icons-vue';
+import { alignElement } from 'dom-align';
+import { active } from 'sortablejs';
 
 const { hasPermission } = usePermission();
 let activeKey = ref('device');
 const treeData = ref<TreeProps['treeData']>([]);
 const selectedKeys = ref<string[]>([]);
 const expandedKeys = ref<string[]>([]);
+const deviceType = ref(''); // 监测设备类型
+const systemType = ref('');
 const systemID = ref(''); // 系统监测时,系统id
+const dataSource = shallowRef([]); // 实时监测数据
+let startMonitorTimer = 0;
+const monitorTable = ref();
+const isRefresh = ref(true);
+const treeNodeTitle = ref(''); // 选中的树形标题
+const deviceList = ref<any[]>([]); // 设备列表
+const monitorList = ref<any[]>([]); // 监测数据列表
+let timer: null | NodeJS.Timeout = undefined;
+// 当前展开的行key数组
+const expandedRowKeys = ref([]);
+
+// 加载状态映射
+const loadingMap = reactive({});
+
+// 分页配置
+const pagination = reactive({
+  current: 1,
+  pageSize: 10,
+  total: computed(() => deviceList.value.length),
+  showSizeChanger: true,
+  pageSizeOptions: ['10', '20', '50'],
+  onChange: (page, size) => {
+    pagination.current = page;
+    pagination.pageSize = size;
+  },
+  onShowSizeChange: (current, size) => {
+    pagination.current = 1;
+    pagination.pageSize = size;
+  },
+});
+// 切换tab页面
+async function onChangeTab(tab) {
+  activeKey.value = tab;
+  if (activeKey.value == 'device') {
+    // 获取监测接口
+  } else if (activeKey.value == 'history') {
+    // 获取历史数据
+  }
+}
 //树形菜单选择事件
-const onSelect: TreeProps['onSelect'] = (keys, e) => {};
+const onSelect: TreeProps['onSelect'] = (keys, e) => {
+  deviceType.value = '';
+  systemID.value = '';
+  deviceList.value = [];
+  const title = e.node.title;
+  if (e.node.parent && e.node.parent.node.type.toString().startsWith('sys')) {
+    systemType.value = e.node.parent.node.type;
+    if (deviceType.value != e.node.parent.node.type) deviceType.value = e.node.parent.node.type;
+    systemID.value = e.node.type;
+  } else {
+    systemType.value = e.node.type;
+    if (deviceType.value != e.node.type) deviceType.value = e.node.type;
+  }
+  getDeviceList(deviceType.value);
+  // clearTimeout(timer);
+  // timer = undefined;
+  // if (startMonitorTimer) {
+  //   clearTimeout(startMonitorTimer);
+  // }
+  // dataSource.value = [];
+  // // monitorTable.value.resetPagination();
+  // if (!startMonitorTimer) {
+  //   startMonitorTimer = setTimeout(() => {
+  //     expandedKeys.value = keys;
+  //     selectedKeys.value = keys;
+  //     treeNodeTitle.value = e.node.title;
+  //     if (e.node.children?.length < 1 && timer) {
+  //       // getMonitor(true);
+  //     }
+  //   }, 1000);
+  // }
+};
+
+async function findTreeDataValue(obj) {
+  const findDeviceType = (data: any[], obj, flag = true) => {
+    return data.find((item: any) => {
+      if (item.children.length > 0) {
+        findDeviceType(item.children, obj);
+      }
+      // debugger;
+      if (obj.deviceType && obj.deviceType.startsWith('sys_')) {
+        // debugger;
+        if (item.type == obj.deviceid) {
+          deviceType.value = 'sys';
+          systemID.value = obj.deviceid;
+          selectedKeys.value = [item.key];
+          expandedKeys.value = [item.key];
+          treeNodeTitle.value = item.title;
+        }
+      } else {
+        if (!flag) {
+          if (obj.deviceType && item.type.startsWith(obj.deviceType)) {
+            deviceType.value = item.type;
+            selectedKeys.value = [item.key];
+            expandedKeys.value = [item.key];
+            treeNodeTitle.value = item.title;
+            return true;
+          }
+          return false;
+        } else {
+          if (obj.deviceType && item.type == obj.deviceType) {
+            deviceType.value = item.type;
+            selectedKeys.value = [item.key];
+            expandedKeys.value = [item.key];
+            treeNodeTitle.value = item.title;
+            return true;
+          }
+          return false;
+        }
+      }
+      return false;
+    });
+  };
+  const flag = findDeviceType(treeData.value, obj);
+  if (!flag) {
+    findDeviceType(treeData.value, obj, false);
+  }
+  // 无类型时
+  if (!treeNodeTitle.value && treeData.value && treeData.value[0] && treeData.value[0]['children']) {
+    const defaultData = treeData.value[0]['children'][0];
+    if (deviceType.value !== defaultData.type) deviceType.value = defaultData.type;
+    selectedKeys.value = [defaultData.key as string];
+    expandedKeys.value = [defaultData.key as string];
+    treeNodeTitle.value = defaultData.title;
+  }
+
+  // if (timer === undefined) {
+  //   timer = null;
+  //   await getDataSource();
+  //   getMonitor(true);
+  // }
+}
 // 获取树形菜单数据
 async function getDeviceType(sysType?) {
-  if (treeData.value?.length > 0) return;
+  // if (treeData.value?.length > 0) return;
   const result = await getDeviceTypeList({});
   if (result.length > 0) {
     const dataSource = <TreeProps['treeData']>[];
@@ -136,33 +276,15 @@ async function getDeviceType(sysType?) {
     treeData.value = getData(result, dataSource, key);
   }
 }
-// 设备数据结构
-const deviceList = ref([
-  {
-    id: 'D001',
-    name: '模拟设备1',
-    status: '在线',
-    monitoringFields: [], // 初始为空,点击时加载
-  },
-  {
-    id: 'D002',
-    name: '模拟设备2',
-    status: '离线',
-    monitoringFields: [],
-  },
-  {
-    id: 'D003',
-    name: '模拟设备3',
-    status: '在线',
-    monitoringFields: [],
-  },
-]);
-
-// 当前展开的行key数组
-const expandedRowKeys = ref([]);
-
-// 加载状态映射
-const loadingMap = reactive({});
+// 根据选择设备获取设备列表
+async function getDeviceList(deviceTypeVal?) {
+  if (!deviceTypeVal) return;
+  const params: any = {
+    devKind: deviceTypeVal,
+  };
+  const result = await getDeviceListByType(params);
+  deviceList.value = result.records;
+}
 
 // 外层表格列配置
 const outerColumns = [
@@ -170,16 +292,25 @@ const outerColumns = [
     title: '设备ID',
     dataIndex: 'id',
     key: 'id',
+    align: 'center',
+  },
+  {
+    title: '安装位置',
+    dataIndex: 'strinstallpos',
+    key: 'strinstallpos',
+    align: 'center',
   },
   {
-    title: '设备名称',
-    dataIndex: 'name',
-    key: 'name',
+    title: '设备类型',
+    dataIndex: 'devicekind_dictText',
+    key: 'devicekind_dictText',
+    align: 'center',
   },
   {
     title: '状态',
-    dataIndex: 'status',
-    key: 'status',
+    dataIndex: 'netStatus',
+    key: 'netStatus',
+    align: 'center',
     customRender: ({ text }) => {
       text = '在线';
       return `${text}`;
@@ -190,34 +321,37 @@ const outerColumns = [
 // 内层表格列配置
 const innerColumns = [
   {
-    title: '监测字段',
-    dataIndex: 'field',
-    key: 'field',
-    width: '40%',
+    title: '地址',
+    dataIndex: 'plcAddr',
+    key: 'plcAddr',
+    align: 'center',
+  },
+  {
+    title: '数据code',
+    dataIndex: 'valueCode',
+    align: 'center',
+    key: 'valueCode',
+  },
+  {
+    title: '数据名称',
+    dataIndex: 'valueName',
+    align: 'center',
+    key: 'valueName',
   },
   {
-    title: '当前值',
+    title: '数据值',
     dataIndex: 'value',
+    align: 'center',
     key: 'value',
-    width: '30%',
   },
   {
-    title: '单位',
-    dataIndex: 'unit',
-    key: 'unit',
-    width: '30%',
+    title: '时间',
+    dataIndex: 'time',
+    align: 'center',
+    key: 'time',
   },
 ];
 
-// 分页配置
-const pagination = reactive({
-  current: 1,
-  pageSize: 10,
-  total: 3,
-  showSizeChanger: true,
-  pageSizeOptions: ['10', '20', '50'],
-});
-
 // 切换展开状态
 const toggleExpand = (deviceId) => {
   const index = expandedRowKeys.value.indexOf(deviceId);
@@ -235,48 +369,19 @@ const toggleExpand = (deviceId) => {
 const loadMonitoringData = async (deviceId) => {
   const device = deviceList.value.find((d) => d.id === deviceId);
 
-  if (device && device.monitoringFields.length === 0) {
-    loadingMap[deviceId] = true;
-    try {
-      // 模拟API请求
-      await new Promise((resolve) => setTimeout(resolve, 800));
-      // 根据设备ID加载对应数据
-      device.monitoringFields = mockFetchMonitoringData(deviceId);
-    } catch (error) {
-      console.error(`加载设备 ${deviceId} 数据失败:`, error);
-    } finally {
-      loadingMap[deviceId] = false;
-    }
+  loadingMap[deviceId] = true;
+  try {
+    const result = await getDevMonitorListById({ devId: deviceId });
+    monitorList.value = Object.values(result.readData);
+  } catch (error) {
+    console.error(`加载设备 ${deviceId} 数据失败:`, error);
+  } finally {
+    loadingMap[deviceId] = false;
   }
 };
 
-// 值样式分类
-const getValueClass = (value) => {
-  if (value > 30) return 'high-value';
-  if (value < 10) return 'low-value';
-  return 'normal-value';
-};
-
-// 模拟API获取监测数据
-const mockFetchMonitoringData = (deviceId) => {
-  const dataMap = {
-    D001: [
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-    ],
-    D002: [
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-    ],
-    D003: [
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-    ],
-  };
-  return dataMap[deviceId] || [];
-};
 onMounted(async () => {
-  getDeviceType();
+  await getDeviceType();
 });
 onUnmounted(() => {});
 </script>
@@ -634,13 +739,12 @@ onUnmounted(() => {});
     }
 
     .zxm-tree-node-content-wrapper.zxm-tree-node-selected {
-      background-color: var(--tree-node-select);
+      background-color: #00b1c8;
     }
 
     .zxm-tree-node-content-wrapper:hover {
-      background-color: var(--tree-node-hover);
+      background-color: #00b1c8;
     }
-
     input {
       height: 0px !important;
     }

+ 70 - 15
src/views/vent/dataCenter/infoCenter/index.vue

@@ -4,42 +4,42 @@
     <div class="company-content">
       <div class="content-item item-1">
         <infoBox class="infoBox1">
-          <template #title> 系统数据量 </template>
+          <template #title> 设备数据量 </template>
           <template #container>
             <div class="content-wrapper wrapper-1 grid">
               <div class="data-item">
                 <div class="item-icon icon1"></div>
                 <div>
-                  <div class="label">接入系统数量</div>
-                  <div class="value">262 </div>
+                  <div class="label">接入设备数量</div>
+                  <div class="value">{{ deviceData.deviceCount }} </div>
                 </div>
               </div>
               <div class="data-item">
                 <div class="item-icon icon2"></div>
                 <div>
                   <div class="label">接入点位数量</div>
-                  <div class="value status-normal">14521</div>
+                  <div class="value status-normal">{{ deviceData.monitorParamsCount }}</div>
                 </div>
               </div>
               <div class="data-item">
                 <div class="item-icon icon3"></div>
                 <div>
                   <div class="label">数据存储量</div>
-                  <div class="value status-normal">14521</div>
+                  <div class="value status-normal">{{ deviceData.databaseDiskUsage }}</div>
                 </div>
               </div>
               <div class="data-item">
                 <div class="item-icon icon4"></div>
                 <div>
                   <div class="label">消息总数量(条)</div>
-                  <div class="value status-normal">14521</div>
+                  <div class="value status-normal">{{ deviceData.collectTotalNum }}</div>
                 </div>
               </div>
               <div class="data-item">
                 <div class="item-icon icon5"></div>
                 <div>
                   <div class="label">共享接口数量</div>
-                  <div class="value status-normal">14521</div>
+                  <div class="value status-normal">0</div>
                 </div>
               </div>
             </div>
@@ -51,7 +51,7 @@
           <template #title> 每日采集数据量 </template>
           <template #container>
             <div class="content-wrapper">
-              <CustomChart :chart-config="dailyNumOption" :chart-data="dailyNumData" height="250px" />
+              <CustomChart :chart-config="dailyNumOption" :chart-data="deviceData" height="245px" />
             </div>
           </template>
         </infoBox>
@@ -59,17 +59,17 @@
           <template #title> 系统数据量排名 </template>
           <template #container>
             <div class="content-wrapper">
-              <a-table size="small" :dataSource="sysData" :columns="sysDataColumn" :pagination="false" />
+              <a-table size="small" :dataSource="deviceData.collectDataByStationList" :columns="sysDataColumn" :pagination="false" />
             </div>
           </template>
         </infoBox>
       </div>
       <div class="content-item item-3">
         <infoBox class="infoBox4">
-          <template #title> 系统接入情况 </template>
+          <template #title> 设备接入情况 </template>
           <template #container>
             <div class="content-wrapper">
-              <a-table size="small" :dataSource="accessStatusData" :columns="accessStatusColumn" :pagination="false">
+              <a-table size="small" :dataSource="accessStatusData" :columns="accessStatusColumn" :pagination="pagination" @change="pageChange">
                 <template #action="{ record }">
                   <div class="option-cont">
                     <div class="view-icon"></div>
@@ -85,16 +85,67 @@
   </div>
 </template>
 <script lang="ts" setup>
-  import { ref } from 'vue';
+  import { ref, onMounted, reactive } from 'vue';
   import customHeader from '/@/components/vent/customHeader.vue';
   import infoBox from './components/infoBox.vue';
-  import { sysDataColumn, sysData, accessStatusColumn, accessStatusData, dailyNumOption, dailyNumData } from './infoCenter.data';
+  import { sysDataColumn, accessStatusColumn, dailyNumOption } from './infoCenter.data';
   import CustomChart from '@/views/vent/home/configurable/components/detail/CustomChart.vue';
+  import { getDeviceAll, getHomepageSummaryIndexes } from './infoCenter.api';
   let mainTitle = ref('智能通风数据中心');
-
+  //分页参数配置
+  const pagination = reactive({
+    current: 1, // 当前页码
+    pageSize: 5, // 每页显示条数
+    total: 0, // 总条目数,后端返回
+    // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
+  });
+  // 设备接入情况数据
+  const accessStatusData = ref([]);
+  // 数据中心首页设备数据
+  const deviceData = ref({
+    monitorParamsCount: 0,
+    deviceCount: 0,
+    databaseDiskUsage: 0,
+    collectTotalNum: 0,
+    collectDataByStationList: [],
+    collectDataByDayList: [],
+  });
+  // 查看数据
   function viewData(record) {
     console.log(record);
   }
+  //分页切换
+  const pageChange = async (val) => {
+    pagination.current = val.current;
+    pagination.pageSize = val.pageSize;
+    const res = await getDeviceAll({
+      pageNo: pagination.current,
+      pageSize: pagination.pageSize,
+    });
+    accessStatusData.value = res.records; // 赋值给响应式变量
+    pagination.total = res.total; // 更新总条数
+  };
+  // 获取设备数据接口
+  const fetchDeviceData = async () => {
+    try {
+      // 获取首页汇总指标数据
+      deviceData.value = await getHomepageSummaryIndexes();
+      // 获取设备接入情况数据
+      const response = await getDeviceAll({
+        pageNo: pagination.current,
+        pageSize: pagination.pageSize,
+      });
+      accessStatusData.value = response.records; // 赋值给响应式变量
+      pagination.total = response.total; // 更新总条数
+    } catch (error) {
+      console.error('获取设备数据失败:', error);
+    }
+  };
+
+  // 页面挂载时调用接口获取数据
+  onMounted(async () => {
+    await fetchDeviceData();
+  });
 </script>
 <style lang="less" scoped>
   @font-face {
@@ -118,7 +169,7 @@
       left: 0;
       width: 100%;
       height: calc(100% - 50px);
-      padding: 10px 20px;
+      padding: 20px 20px 10px 20px;
       --image-border1: url('/@/assets/images/dataCenter/infoCenter/info-border1.png');
       --image-border2: url('/@/assets/images/dataCenter/infoCenter/info-border2.png');
       --image-border3: url('/@/assets/images/dataCenter/infoCenter/info-border3.png');
@@ -163,6 +214,7 @@
       }
       .item-3 {
         height: 40%;
+        padding-bottom: 0;
         :deep(table) {
           border-collapse: collapse !important;
           // border-spacing: 0 10px !important;
@@ -190,6 +242,9 @@
             }
           }
         }
+        .box-container {
+          overflow: hidden;
+        }
       }
       .infoBox1 {
         background-color: var(--image-border1) no-repeat;

+ 26 - 0
src/views/vent/dataCenter/infoCenter/infoCenter.api.ts

@@ -0,0 +1,26 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  getDeviceAll = '/dataCenter/compute/deviceData/getDeviceAll',
+  getHomepageSummaryIndexes = '/sjzx/modelreq/safety/homepage/getHomepageSummaryIndexes',
+}
+//数据列表
+export const getDeviceAll = (params) =>
+  defHttp.post({
+    headers: {
+      'X-Access-Token':
+        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzU5ODQxMTcwfQ.fHaM3l-d88tUSLOs8sstXsDuSCn6Agbj_EMZMgV6waw',
+    },
+    url: Api.getDeviceAll,
+    params,
+  });
+
+//首页数据详情
+export const getHomepageSummaryIndexes = () =>
+  defHttp.get({
+    headers: {
+      'X-Access-Token':
+        'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNzU5ODQxMTcwfQ.fHaM3l-d88tUSLOs8sstXsDuSCn6Agbj_EMZMgV6waw',
+    },
+    url: Api.getHomepageSummaryIndexes,
+  });

+ 59 - 93
src/views/vent/dataCenter/infoCenter/infoCenter.data.ts

@@ -45,7 +45,7 @@ export const sysDataColumn: BasicColumn[] = [
                 position: 'absolute',
                 top: '50%',
                 left: '50%',
-                transform: 'translate(-50%, -50%)', 
+                transform: 'translate(-50%, -50%)',
                 color: '#fff',
                 fontSize: '14px',
                 fontWeight: 'bold',
@@ -58,41 +58,20 @@ export const sysDataColumn: BasicColumn[] = [
     },
   },
   {
-    title: '系统名称',
-    dataIndex: 'sysName',
+    title: '设备id',
+    dataIndex: 'sub_id',
     align: 'center',
+    ifShow: false,
   },
   {
-    title: '数量',
-    dataIndex: 'sysNum',
+    title: '设备名称',
+    dataIndex: 'strName',
     align: 'center',
   },
-];
-// 系统接入情况数据
-export const sysData = [
-  {
-    sysName: 'wscc',
-    sysNum: 32,
-  },
-  {
-    sysName: 'wscc',
-    sysNum: 33,
-  },
-  {
-    sysName: 'wscc',
-    sysNum: 34,
-  },
   {
-    sysName: 'wscc',
-    sysNum: 35,
-  },
-  {
-    sysName: 'wscc',
-    sysNum: 35,
-  },
-  {
-    sysName: 'wscc',
-    sysNum: 35,
+    title: '数量',
+    dataIndex: 'total_num',
+    align: 'center',
   },
 ];
 
@@ -104,24 +83,24 @@ export const accessStatusColumn: BasicColumn[] = [
     customRender: ({ index }: { index: number }) => `${index + 1}`,
   },
   {
-    title: '系统名称',
-    dataIndex: 'sysName',
+    title: '设备名称',
+    dataIndex: 'devicekind_dictText',
     align: 'center',
   },
 
   {
-    title: '系统接入时间',
-    dataIndex: 'accessTime',
+    title: '设备接入时间',
+    dataIndex: 'createTime',
     align: 'center',
   },
   {
     title: '点位数量',
-    dataIndex: 'pointNum',
+    dataIndex: 'monitorPointNum',
     align: 'center',
   },
   {
     title: '运行状态',
-    dataIndex: 'runStatus',
+    dataIndex: 'netStatus',
     align: 'center',
   },
   {
@@ -137,37 +116,6 @@ export const accessStatusColumn: BasicColumn[] = [
     slots: { customRender: 'action' },
   },
 ];
-// 系统接入情况数据
-export const accessStatusData = [
-  {
-    sysName: '1',
-    accessTime: '2025.10.01',
-    pointNum: 32,
-    runStatus: '1',
-    dataUpdateTime: '2025.10.01',
-  },
-  {
-    sysName: '2',
-    accessTime: '2025.10.02',
-    pointNum: 32,
-    runStatus: '2',
-    dataUpdateTime: '2025.10.02',
-  },
-  {
-    sysName: '3',
-    accessTime: '2025.10.02',
-    pointNum: 32,
-    runStatus: '3',
-    dataUpdateTime: '2025.10.02',
-  },
-  {
-    sysName: '3',
-    accessTime: '2025.10.02',
-    pointNum: 32,
-    runStatus: '3',
-    dataUpdateTime: '2025.10.02',
-  },
-];
 // 每日采集数据表格属性
 export const dailyNumOption: ModuleDataChart = {
   type: 'bar',
@@ -175,54 +123,72 @@ export const dailyNumOption: ModuleDataChart = {
   legend: { show: false },
   xAxis: [{ show: true }],
   yAxis: [{ show: true, name: '', position: 'left' }],
-  series: [{ readFrom: 'history', xprop: 'time', yprop: 'val', label: '' }],
+  series: [{ readFrom: 'collectDataByDayList', xprop: 'day', yprop: 'total_count', label: '' }],
 };
-// 每日采集数据
-export const dailyNumData = {
-  history: [
+
+export const deviceData = {
+  monitorParamsCount: 1727,
+  deviceCount: 4,
+  databaseDiskUsage: 10165,
+  collectDataByStationList: [
+    {
+      sub_id: '1696417397868986370',
+      strName: '调试http协议束管',
+      total_num: 258,
+    },
     {
-      time: '2025-10-13',
-      val: '113',
+      sub_id: '1696417397868986370',
+      strName: '调试http协议束管',
+      total_num: 256,
     },
     {
-      time: '2025-10-14',
-      val: '153',
+      sub_id: '1696417397868986370',
+      strName: '调试http协议束管',
+      total_num: 254,
     },
     {
-      time: '2025-10-15',
-      val: '163',
+      sub_id: '1696417397868986370',
+      strName: '调试http协议束管',
+      total_num: 252,
+    },
+  ],
+  collectTotalNum: 258,
+  collectDataByDayList: [
+    {
+      day: '2025-10-29',
+      total_count: '30',
     },
     {
-      time: '2025-10-16',
-      val: '193',
+      day: '2025-10-30',
+      total_count: '165',
     },
     {
-      time: '2025-10-17',
-      val: '203',
+      day: '2025-10-31',
+      total_count: '63',
     },
     {
-      time: '2025-10-18',
-      val: '203',
+      day: '2025-11-01',
+      total_count: '30',
     },
     {
-      time: '2025-10-19',
-      val: '223',
+      day: '2025-11-02',
+      total_count: '165',
     },
     {
-      time: '2025-10-20',
-      val: '183',
+      day: '2025-11-03',
+      total_count: '63',
     },
     {
-      time: '2025-10-21',
-      val: '153',
+      day: '2025-11-04',
+      total_count: '30',
     },
     {
-      time: '2025-10-22',
-      val: '183',
+      day: '2025-11-05',
+      total_count: '165',
     },
     {
-      time: '2025-10-23',
-      val: '153',
+      day: '2025-11-06',
+      total_count: '63',
     },
   ],
 };

+ 9 - 62
src/views/vent/dataCenter/stationCenter/device.api.ts

@@ -1,67 +1,14 @@
 import { defHttp } from '/@/utils/http/axios';
 
 enum Api {
-  list = '/monitor/device',
-  baseList = '/safety/ventanalyDeviceInfo/list',
-  // deviceTypeList = '/safety/ventanalyDeviceInfo/DeviceKind/query',
-  // deviceTypeList = '/sys/dict/DeviceKind/queryBySystem',
+  subStationList = '/safety/ventanalySubStation/alllist',
   deviceTypeList = '/safety/ventanalyDeviceInfo/DeviceKind/queryBySystem',
-  itemList = '/sys/dictItem/list',
-  devPosition = '/sys/dict/getDictItems/devPosVisible',
-  getDepartmentInfo = '/monitor/getDepartmentInfo',
-  listdays = '/safety/ventanalyMonitorData/listdays',
-  getHistoryData = '/monitor/history/getHistoryData',
-  safetyDeviceList = '/monitor/codeDict',
-  exportXlsUrl = '/monitor/exportXls',
-  queryNowGasInsInfo = '/safety/gasDayReport/queryNowGasInsInfo', //查询当前各班瓦斯巡检信息
-  queryNowGasSta = '/safety/gasDayReport/queryNowGasSta',
-  queryReportData = '/safety/reportLocalData/queryReportData', //查询瓦斯日报列表
-  getDeviceListBySubId = '/safety/ventanalyDeviceInfo/getDeviceListBySubId', //查询分站
-  getDeviceHistoryData = '/safety/ventanalyMonitorData/getRealHistoryData', //查询设备历史数据
-  getRegulation = '/monitor/getDeviceRegulation',
+  deviceList = '/compute/deviceData/getDeviceAll',
+  devMonitorList = '/compute/deviceData/getDeviceMonitorInfo',
 }
-//分站全部列表
-export const getListAll = () => defHttp.post({ url: Api.getDeviceListBySubId });
-/**
- * 列表接口
- * @param params
- */
-export const list = (params) => defHttp.post({ url: Api.list, params });
-
-/**
- * 保存或者更新用户
- * @param params
- */
-export const getDeviceList = (params) => defHttp.get({ url: Api.baseList, params });
-
-export const getDeviceTypeList = (params) => defHttp.get({ url: Api.deviceTypeList, params });
-
-export const itemList = (params) => defHttp.get({ url: Api.itemList, params });
-export const devPosition = (params) => defHttp.get({ url: Api.devPosition, params });
-
-export const getDepartmentInfo = (params) => defHttp.get({ url: Api.getDepartmentInfo, params });
-
-export const listdays = (params) => defHttp.get({ url: Api.listdays, params });
-export const getHistoryData = (params) => defHttp.post({ url: Api.getHistoryData, params });
-export const safetyDeviceList = (params) => defHttp.post({ url: Api.safetyDeviceList, params });
-export const queryNowGasInsInfo = (params) => defHttp.post({ url: Api.queryNowGasInsInfo, params });
-
-export const getExportUrl = Api.exportXlsUrl;
-/**
- * 列表接口
- * @param params
- */
-export const queryNowGasSta = (params) => defHttp.post({ url: Api.queryNowGasSta, params });
-/**
- * 瓦斯日报列表
- * @param params
- */
-export const queryReportData = (params) => defHttp.post({ url: Api.queryReportData, params });
-
-/**
- * 设备历史数据接口
- * @param params
- */
-export const getDeviceHistoryData = (params) => defHttp.post({ url: Api.getDeviceHistoryData, data: params });
-
-export const getRegulation = (params) => defHttp.post({ url: Api.getRegulation, params });
+// 分站查询接口
+export const subStationList = (params) => defHttp.get({ url: Api.subStationList, params });
+//根据设备类型获取设备列表
+export const getDeviceListByType = (params) => defHttp.post({ url: Api.deviceList, params });
+//根据设备id获取设备监控数据
+export const getDevMonitorListById = (params) => defHttp.post({ url: Api.devMonitorList, params });

+ 928 - 100
src/views/vent/dataCenter/stationCenter/index.vue

@@ -81,7 +81,7 @@
 </template>
 
 <script setup lang="ts">
-import { ref, nextTick, reactive, onMounted, onUnmounted, inject } from 'vue';
+import { ref, nextTick, computed, reactive, onMounted, onUnmounted, inject } from 'vue';
 import { usePermission } from '/@/hooks/web/usePermission';
 import customHeader from '/@/components/vent/customHeader.vue';
 import { AesEncryption } from '/@/utils/cipher';
@@ -89,6 +89,7 @@ import { loginCipher } from '/@/settings/encryptionSetting';
 import { message, TreeProps } from 'ant-design-vue';
 import { list, getDeviceList, getDeviceTypeList, devPosition, getDepartmentInfo, getExportUrl, getRegulation } from './device.api';
 import { DownOutlined, RightOutlined } from '@ant-design/icons-vue';
+import { subStationList } from './device.api';
 
 const { hasPermission } = usePermission();
 let activeKey = ref('device');
@@ -96,44 +97,37 @@ const treeData = ref<TreeProps['treeData']>([]);
 const selectedKeys = ref<string[]>([]);
 const expandedKeys = ref<string[]>([]);
 const systemID = ref(''); // 系统监测时,系统id
+let cardList = ref<any[]>(); //分站列表
+let openNum = ref(0);
+let clsoeNum = ref(0);
+
+// 分页配置
+const pagination = reactive({
+  current: 1,
+  pageSize: 10,
+  total: computed(() => deviceList.value.length),
+  showSizeChanger: true,
+  pageSizeOptions: ['10', '20', '50'],
+  onChange: (page, size) => {
+    pagination.current = page;
+    pagination.pageSize = size;
+  },
+  onShowSizeChange: (current, size) => {
+    pagination.current = 1;
+    pagination.pageSize = size;
+  },
+});
 //树形菜单选择事件
 const onSelect: TreeProps['onSelect'] = (keys, e) => {};
-// 获取树形菜单数据
-async function getDeviceType(sysType?) {
-  if (treeData.value?.length > 0) return;
-  const result = await getDeviceTypeList({});
-  if (result.length > 0) {
-    const dataSource = <TreeProps['treeData']>[];
-    let key = '0';
-    const getData = (resultList, dataSourceList, keyVal) => {
-      resultList.forEach((item, index) => {
-        if (item.deviceType != 'sys' && item.children && item.children.length > 0) {
-          const children = getData(item.children, [], `${keyVal}-${index}`);
-          // 判断关键阻力路线
-          if (item.itemValue.startsWith(sysType) && children[0]) {
-            systemID.value = item.children[0]['itemValue'];
-          }
-
-          dataSourceList.push({
-            children: children,
-            title: item.itemText,
-            key: `${keyVal}-${index}`,
-            type: item.itemValue,
-            parentKey: `${keyVal}`,
-          });
-        } else {
-          dataSourceList.push({
-            children: [],
-            title: item.itemText,
-            key: `${keyVal}-${index}`,
-            type: item.itemValue,
-            parentKey: `${keyVal}`,
-          });
-        }
-      });
-      return dataSourceList;
-    };
-    treeData.value = getData(result, dataSource, key);
+//获取分站信息
+async function getSubStationList() {
+  let res = await subStationList({ strtype: 'modbus' });
+  if (res.length != 0) {
+    cardList.value = res;
+    openNum.value = cardList.value?.filter((v) => v.linkstatus == 1)['length'];
+    clsoeNum.value = cardList.value?.filter((v) => v.linkstatus == 0)['length'];
+  } else {
+    cardList.value = [];
   }
 }
 // 设备数据结构
@@ -163,6 +157,201 @@ const expandedRowKeys = ref([]);
 
 // 加载状态映射
 const loadingMap = reactive({});
+// 根据选择设备获取设备列表
+async function getDeviceList(deviceTypeVal?) {
+  // if (!deviceTypeVal) return;
+  const params: any = {
+    devKind: deviceTypeVal,
+  };
+  const result = {
+    records: [
+      {
+        id: '1965325207547695105',
+        strname: '束管1',
+        strinstallpos: '束管1',
+        devicekind: 'bundletube',
+        strtype: 'bundletube_auto',
+        typename: null,
+        flength: null,
+        fsectarea: null,
+        planedVa: null,
+        regulation: null,
+        elevation: null,
+        nsubstationid: '1696417397868986370',
+        stationname: '调试http协议',
+        strremark: null,
+        createBy: 'admin',
+        createTime: '2025-09-09 16:03:38',
+        updateBy: null,
+        updateTime: null,
+        isSelfDevice: 0,
+        status: 1,
+        monitorflag: 1,
+        testflag: 0,
+        sysOrgCode: 'A02A02',
+        orgCode: 'A02',
+        readData: {},
+        linkInfo: null,
+        stationids: null,
+        password: null,
+        strserno: 'sg001',
+        devgroup: null,
+        panel: null,
+        coalseam: null,
+        other1: null,
+        other2: null,
+        other3: null,
+        other4: null,
+        info: {},
+        linkId: null,
+        addrIndex: null,
+        standCode: null,
+        stationtype: null,
+        otherInfo: null,
+        programList: null,
+        debugFlag: 0,
+        orderNum: 0,
+        insType: null,
+        disTeamId: null,
+        isSensor: null,
+        nameEarly: null,
+        nameNoon: null,
+        nameNight: null,
+        disTeamName: null,
+        gasCheckTaskId: null,
+        isExistGasCheckTask: null,
+        netStatus: null,
+        devicekind_dictText: '束管监测',
+        isSelfDevice_dictText: '其他厂家',
+        monitorflag_dictText: '监测',
+        testflag_dictText: '否',
+      },
+      {
+        id: '1965325207568666626',
+        strname: '束管2',
+        strinstallpos: '束管2',
+        devicekind: 'bundletube',
+        strtype: 'bundletube_auto',
+        typename: null,
+        flength: null,
+        fsectarea: null,
+        planedVa: null,
+        regulation: null,
+        elevation: null,
+        nsubstationid: '1696417397868986370',
+        stationname: '调试http协议',
+        strremark: null,
+        createBy: 'admin',
+        createTime: '2025-09-09 16:03:38',
+        updateBy: null,
+        updateTime: null,
+        isSelfDevice: 0,
+        status: 1,
+        monitorflag: 1,
+        testflag: 0,
+        sysOrgCode: 'A02A02',
+        orgCode: 'A02',
+        readData: {},
+        linkInfo: null,
+        stationids: null,
+        password: null,
+        strserno: 'sg002',
+        devgroup: null,
+        panel: null,
+        coalseam: null,
+        other1: null,
+        other2: null,
+        other3: null,
+        other4: null,
+        info: {},
+        linkId: null,
+        addrIndex: null,
+        standCode: null,
+        stationtype: null,
+        otherInfo: null,
+        programList: null,
+        debugFlag: 0,
+        orderNum: 0,
+        insType: null,
+        disTeamId: null,
+        isSensor: null,
+        nameEarly: null,
+        nameNoon: null,
+        nameNight: null,
+        disTeamName: null,
+        gasCheckTaskId: null,
+        isExistGasCheckTask: null,
+        netStatus: null,
+        devicekind_dictText: '束管监测',
+        isSelfDevice_dictText: '其他厂家',
+        monitorflag_dictText: '监测',
+        testflag_dictText: '否',
+      },
+      {
+        id: '1965325207568666627',
+        strname: '束管3',
+        strinstallpos: '束管3',
+        devicekind: 'bundletube',
+        strtype: 'bundletube_auto',
+        typename: null,
+        flength: null,
+        fsectarea: null,
+        planedVa: null,
+        regulation: null,
+        elevation: null,
+        nsubstationid: '1696417397868986370',
+        stationname: '调试http协议',
+        strremark: null,
+        createBy: 'admin',
+        createTime: '2025-09-09 16:03:38',
+        updateBy: null,
+        updateTime: null,
+        isSelfDevice: 0,
+        status: 1,
+        monitorflag: 1,
+        testflag: 0,
+        sysOrgCode: 'A02A02',
+        orgCode: 'A02',
+        readData: {},
+        linkInfo: null,
+        stationids: null,
+        password: null,
+        strserno: 'sg003',
+        devgroup: null,
+        panel: null,
+        coalseam: null,
+        other1: null,
+        other2: null,
+        other3: null,
+        other4: null,
+        info: {},
+        linkId: null,
+        addrIndex: null,
+        standCode: null,
+        stationtype: null,
+        otherInfo: null,
+        programList: null,
+        debugFlag: 0,
+        orderNum: 0,
+        insType: null,
+        disTeamId: null,
+        isSensor: null,
+        nameEarly: null,
+        nameNoon: null,
+        nameNight: null,
+        disTeamName: null,
+        gasCheckTaskId: null,
+        isExistGasCheckTask: null,
+        netStatus: null,
+        devicekind_dictText: '束管监测',
+        isSelfDevice_dictText: '其他厂家',
+        monitorflag_dictText: '监测',
+        testflag_dictText: '否',
+      },
+    ],
+  };
+  deviceList.value = result.records;
+}
 
 // 外层表格列配置
 const outerColumns = [
@@ -170,16 +359,25 @@ const outerColumns = [
     title: '设备ID',
     dataIndex: 'id',
     key: 'id',
+    align: 'center',
   },
   {
-    title: '设备名称',
-    dataIndex: 'name',
-    key: 'name',
+    title: '安装位置',
+    dataIndex: 'strinstallpos',
+    key: 'strinstallpos',
+    align: 'center',
+  },
+  {
+    title: '设备类型',
+    dataIndex: 'devicekind_dictText',
+    key: 'devicekind_dictText',
+    align: 'center',
   },
   {
     title: '状态',
-    dataIndex: 'status',
-    key: 'status',
+    dataIndex: 'netStatus',
+    key: 'netStatus',
+    align: 'center',
     customRender: ({ text }) => {
       text = '在线';
       return `${text}`;
@@ -190,34 +388,37 @@ const outerColumns = [
 // 内层表格列配置
 const innerColumns = [
   {
-    title: '监测字段',
-    dataIndex: 'field',
-    key: 'field',
-    width: '40%',
+    title: '地址',
+    dataIndex: 'plcAddr',
+    key: 'plcAddr',
+    align: 'center',
   },
   {
-    title: '当前值',
+    title: '数据code',
+    dataIndex: 'valueCode',
+    align: 'center',
+    key: 'valueCode',
+  },
+  {
+    title: '数据名称',
+    dataIndex: 'valueName',
+    align: 'center',
+    key: 'valueName',
+  },
+  {
+    title: '数据值',
     dataIndex: 'value',
+    align: 'center',
     key: 'value',
-    width: '30%',
   },
   {
-    title: '单位',
-    dataIndex: 'unit',
-    key: 'unit',
-    width: '30%',
+    title: '时间',
+    dataIndex: 'time',
+    align: 'center',
+    key: 'time',
   },
 ];
 
-// 分页配置
-const pagination = reactive({
-  current: 1,
-  pageSize: 10,
-  total: 3,
-  showSizeChanger: true,
-  pageSizeOptions: ['10', '20', '50'],
-});
-
 // 切换展开状态
 const toggleExpand = (deviceId) => {
   const index = expandedRowKeys.value.indexOf(deviceId);
@@ -235,48 +436,675 @@ const toggleExpand = (deviceId) => {
 const loadMonitoringData = async (deviceId) => {
   const device = deviceList.value.find((d) => d.id === deviceId);
 
-  if (device && device.monitoringFields.length === 0) {
-    loadingMap[deviceId] = true;
-    try {
-      // 模拟API请求
-      await new Promise((resolve) => setTimeout(resolve, 800));
-      // 根据设备ID加载对应数据
-      device.monitoringFields = mockFetchMonitoringData(deviceId);
-    } catch (error) {
-      console.error(`加载设备 ${deviceId} 数据失败:`, error);
-    } finally {
-      loadingMap[deviceId] = false;
-    }
+  loadingMap[deviceId] = true;
+  try {
+    const result = {
+      msgType: null,
+      deviceID: '1965325207568666627',
+      deviceType: 'bundletube_auto',
+      typeName: '束管监测',
+      kindtypeName: '束管监测',
+      deviceName: '束管3',
+      devicePos: '束管3',
+      subStationID: '1696417397868986370',
+      monitorflag: 1,
+      testflag: 0,
+      fsectarea: null,
+      planedVa: null,
+      regulation: null,
+      elevation: null,
+      subStationName: '调试http协议束管',
+      subStationIP: 'http://192.168.1.88:10930/compute/testDta/getSgList',
+      subStationPort: '8930',
+      subStationType: 'http',
+      addrIndex: null,
+      standCode: null,
+      sysOrgCode: 'A02A02',
+      orgCode: 'A02',
+      stationids: null,
+      bakids: null,
+      limits: null,
+      cameras: [],
+      summaryHour: [],
+      summaryDay: [],
+      history: [],
+      majorpath: {},
+      info: null,
+      netStatus: null,
+      frontGateOpenCtrl: null,
+      rearGateOpenCtrl: null,
+      readTime: '2025-10-30 14:31:32',
+      lastSummaryDate: null,
+      paramid: null,
+      readData: {
+        coval: {
+          id: 1611236056970682378,
+          saveid: 0,
+          valueCode: 'coval',
+          valueName: '一氧化碳',
+          value: '12.50',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 4,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'coval',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: null,
+              fmax: -10000.00000999999974737875163555145263671875,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '一氧化碳低于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'coval',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: 1000.000009999999974752427078783512115478515625,
+              fmax: 1000000,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '一氧化碳高于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+          ],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: '读取数据为空',
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: 1,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'co',
+          lastSummaryDate: null,
+        },
+        ch2val: {
+          id: 1611236056970682382,
+          saveid: 0,
+          valueCode: 'ch2val',
+          valueName: '乙烯',
+          value: '0.00',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 4,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'ch2val',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: null,
+              fmax: -10000.00000999999974737875163555145263671875,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '乙烯低于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'ch2val',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: 1000.000009999999974752427078783512115478515625,
+              fmax: 1000000,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '乙烯高于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+          ],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: '读取数据为空',
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: 1,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'ch2',
+          lastSummaryDate: null,
+        },
+        gasval: {
+          id: 1611236056970682380,
+          saveid: 0,
+          valueCode: 'gasval',
+          valueName: '甲烷',
+          value: '0.40',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 4,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'gasval',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: null,
+              fmax: -10000.00000999999974737875163555145263671875,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '甲烷低于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'gasval',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: 1000.000009999999974752427078783512115478515625,
+              fmax: 1000000,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '甲烷高于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+          ],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: '读取数据为空',
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: 1,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'ch4',
+          lastSummaryDate: null,
+        },
+        chval: {
+          id: 1611236056970682381,
+          saveid: 0,
+          valueCode: 'chval',
+          valueName: '乙炔',
+          value: '0.00',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 4,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'chval',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: null,
+              fmax: -10000.00000999999974737875163555145263671875,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '乙炔低于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'chval',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: 1000.000009999999974752427078783512115478515625,
+              fmax: 1000000,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '乙炔高于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+          ],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: '读取数据为空',
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: 1,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'c2h2',
+          lastSummaryDate: null,
+        },
+        o2val: {
+          id: 1611236056970683001,
+          saveid: 0,
+          valueCode: 'o2val',
+          valueName: '氧气',
+          value: '19.96',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 4,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'o2val',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: null,
+              fmax: -10000.00000999999974737875163555145263671875,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '氧气低于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'o2val',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: 1000.000009999999974752427078783512115478515625,
+              fmax: 1000000,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '氧气高于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+          ],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: '读取数据为空',
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: 1,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'o2',
+          lastSummaryDate: null,
+        },
+        co2val: {
+          id: 1611236056970682379,
+          saveid: 0,
+          valueCode: 'co2val',
+          valueName: '二氧化碳',
+          value: '0.22',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 4,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'co2val',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: null,
+              fmax: -10000.00000999999974737875163555145263671875,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '二氧化碳低于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+            {
+              id: null,
+              limitid: null,
+              devicekind: null,
+              devicetype: null,
+              deviceid: null,
+              eventid: null,
+              eventname: null,
+              monitorcode: 'co2val',
+              valuetype: 2,
+              alarmType: null,
+              relatedCode: null,
+              fmin: 1000.000009999999974752427078783512115478515625,
+              fmax: 1000000,
+              leveltype: 10000,
+              datakind: null,
+              timelength: null,
+              des: '二氧化碳高于限值',
+              maxDeviceid: null,
+              minDeviceid: null,
+              maxCode: null,
+              minCode: null,
+              isVoice: null,
+              isCxVoice: null,
+              voiceFre: null,
+            },
+          ],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: '读取数据为空',
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: 1,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'co2',
+          lastSummaryDate: null,
+        },
+        deviceStatus: {
+          id: 1611236056970682466,
+          saveid: 0,
+          valueCode: 'deviceStatus',
+          valueName: '运行状态',
+          value: '',
+          hourNum: null,
+          dayNum: null,
+          hourAvg: null,
+          hourMax: null,
+          hourMin: null,
+          dayAvg: null,
+          dayMax: null,
+          dayMin: null,
+          hourMaxTime: null,
+          dayMaxTime: null,
+          hourMinTime: null,
+          dayMinTime: null,
+          dictset: null,
+          summaryDate: null,
+          valueType: 3,
+          maxVal: null,
+          minVal: null,
+          limitlevels: [],
+          warnFlag: null,
+          time: '2025-10-30 14:31:32',
+          timelength: null,
+          warnInfo: null,
+          warnRank: null,
+          saveflag: 1,
+          spaceSave: null,
+          avgflag: null,
+          warnKindType: null,
+          isVoice: null,
+          isCxVoice: null,
+          voiceFre: null,
+          plcAddr: 'M49.0',
+          lastSummaryDate: null,
+        },
+      },
+      oldData: {},
+      oldreadTime: null,
+      fclearwidth: null,
+      fperheight: null,
+      nwindow: null,
+      nwindownum: null,
+      sign: null,
+      isRun: null,
+      saveflag: null,
+      spaceSave: 0,
+      linkInfo: null,
+      linkId: null,
+      bakflag: null,
+      password: null,
+      strserno: 'sg003',
+      strRemark: null,
+      other1: null,
+      other2: null,
+      other3: null,
+      sysKind: 'fireS',
+      orderNum: 0,
+      dtype: 'bundletube',
+      nfrontPluseCircle: null,
+      nbackPluseCircle: null,
+    };
+    monitorList.value = Object.values(result.readData);
+  } catch (error) {
+    console.error(`加载设备 ${deviceId} 数据失败:`, error);
+  } finally {
+    loadingMap[deviceId] = false;
   }
-};
-
-// 值样式分类
-const getValueClass = (value) => {
-  if (value > 30) return 'high-value';
-  if (value < 10) return 'low-value';
-  return 'normal-value';
-};
-
-// 模拟API获取监测数据
-const mockFetchMonitoringData = (deviceId) => {
-  const dataMap = {
-    D001: [
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-    ],
-    D002: [
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-    ],
-    D003: [
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-      { field: '模拟数据', value: (Math.random() * 10).toFixed(2), unit: '1' },
-    ],
-  };
-  return dataMap[deviceId] || [];
+  // const result = await getDevMonitorListById({ deviceId });
 };
 onMounted(async () => {
-  getDeviceType();
+  getSubStationList();
+  getDeviceList();
 });
 onUnmounted(() => {});
 </script>

+ 3 - 3
src/views/vent/gas/gasReport/gas-report.api.ts

@@ -8,8 +8,8 @@ enum Api {
   getIsReviewPass = '/safety/gasDayReport/getIsReviewPass',
   getAllUserInfo = '/safety/gasInsCard/getAllUserInfo',
   exportReportByPoi = '/safety/reportInfo/exportReportByPoi',
- queryUserByRoleCode= '/safety/gasInsCard/queryUserByRoleCode',//通过角色编码查询角色下所有用户
- gasServerImg='/gasServerImg',//获取瓦斯巡检图片
+  queryUserByRoleCode = '/safety/gasInsCard/queryUserByRoleCode', //通过角色编码查询角色下所有用户
+  gasServerImg = '/sw/gasServerImg', //获取瓦斯巡检图片
 }
 /**
  * 获取瓦斯日报区队,检测地点下拉选项
@@ -45,4 +45,4 @@ export const exportReportByPoi = (params) => defHttp.post({ url: Api.exportRepor
 
 export const queryUserByRoleCode = (params) => defHttp.get({ url: Api.queryUserByRoleCode, params });
 
-export const gasServerImg = (params) => defHttp.post({ url: Api.gasServerImg, params,responseType: 'blob' });
+export const gasServerImg = (params) => defHttp.post({ url: Api.gasServerImg, params, responseType: 'blob' });

+ 486 - 454
src/views/vent/gas/gasReport/index.vue

@@ -7,8 +7,13 @@
           <a-col :span="4">
             <div class="area-item">
               <div class="item-text">日期区间:</div>
-              <a-date-picker style="width: 220px" :showTime="false" valueFormat="YYYY-MM-DD"
-                v-model:value="searchData.reportTime" placeholder="请选择填报日期" />
+              <a-date-picker
+                style="width: 220px"
+                :showTime="false"
+                valueFormat="YYYY-MM-DD"
+                v-model:value="searchData.reportTime"
+                placeholder="请选择填报日期"
+              />
             </div>
           </a-col>
 
@@ -22,21 +27,18 @@
             <div class="area-item">
               <div class="item-text">上报地点:</div>
               <a-select v-model:value="searchData.strInstallPos" style="width: 220px" placeholder="请选择上报地点">
-                <a-select-option v-for="item in addressList" :key="item" :value="item.value">{{ item.label
-                }}</a-select-option>
+                <a-select-option v-for="item in addressList" :key="item" :value="item.value">{{ item.label }}</a-select-option>
               </a-select>
             </div>
           </a-col>
 
           <a-button type="primary" preIcon="ant-design:search-outlined" @click="getSearch">查询</a-button>
           <a-button preIcon="ant-design:sync-outlined" style="margin: 0px 10px" @click="onReset">重置</a-button>
-          <a-button type="primary" preIcon="ant-design:check-circle-outlined" style="margin-right: 10px"
-            @click="getPassSh">审核通过</a-button>
+          <a-button type="primary" preIcon="ant-design:check-circle-outlined" style="margin-right: 10px" @click="getPassSh">审核通过</a-button>
           <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport">导出日报表</a-button>
           <!-- <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport1"
             style="margin: 0px 10px">导出瓦斯三对照报表</a-button> -->
-          <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport2"
-            style="margin: 0px 10px">导出瓦斯检查小票</a-button>
+          <a-button type="primary" preIcon="ant-design:download-outlined" @click="getExport2" style="margin: 0px 10px">导出瓦斯检查小票</a-button>
           <a-button type="primary" preIcon="ant-design:download-outlined" @click="handleMenuClick">导出班报表</a-button>
           <!-- <a-dropdown>
             <template #overlay>
@@ -64,64 +66,86 @@
 </a-dropdown> -->
         </a-row>
       </div>
-      <a-table :columns="columns" :data-source="tableData" size="small" :scroll="{ y: 500 }" class="tableW"
-        :pagination="pagination" @change="pageChange">
+      <a-table
+        :columns="columns"
+        :data-source="tableData"
+        size="small"
+        :scroll="{ y: 500 }"
+        class="tableW"
+        :pagination="pagination"
+        @change="pageChange"
+      >
         <template #bodyCell="{ column, text, record }">
           <template
-            v-if="column.dataIndex == 'night1' || column.dataIndex == 'night2' || column.dataIndex == 'early1' || column.dataIndex == 'early2' || column.dataIndex == 'noon1' || column.dataIndex == 'noon2'">
-            <a-button class="img-view" type="text" size="small"
-              @click="imgViewClick({ record, dataIndex: column.dataIndex })">查看</a-button>
+            v-if="
+              column.dataIndex == 'night1' ||
+              column.dataIndex == 'night2' ||
+              column.dataIndex == 'early1' ||
+              column.dataIndex == 'early2' ||
+              column.dataIndex == 'noon1' ||
+              column.dataIndex == 'noon2'
+            "
+          >
+            <a-button class="img-view" type="text" size="small" @click="imgViewClick({ record, dataIndex: column.dataIndex })">查看</a-button>
           </template>
-          <template v-if="
-            column.dataIndex == 'o2Night1' ||
-            column.dataIndex == 'o2Night2' ||
-            column.dataIndex == 'o2Early1' ||
-            column.dataIndex == 'o2Early2' ||
-            column.dataIndex == 'o2Noon1' ||
-            column.dataIndex == 'o2Noon2'
-          ">
-            <div :style="{ color: Number(text) >= 18 && Number(text) <= 20.9 ? '#0ae715' : '#ff2313' }">{{ text }}
-            </div>
+          <template
+            v-if="
+              column.dataIndex == 'o2Night1' ||
+              column.dataIndex == 'o2Night2' ||
+              column.dataIndex == 'o2Early1' ||
+              column.dataIndex == 'o2Early2' ||
+              column.dataIndex == 'o2Noon1' ||
+              column.dataIndex == 'o2Noon2'
+            "
+          >
+            <div :style="{ color: Number(text) >= 18 && Number(text) <= 20.9 ? '#0ae715' : '#ff2313' }">{{ text }} </div>
           </template>
-          <template v-if="
-            column.dataIndex == 'coNight1' ||
-            column.dataIndex == 'coNight2' ||
-            column.dataIndex == 'coEarly1' ||
-            column.dataIndex == 'coEarly2' ||
-            column.dataIndex == 'coNoon1' ||
-            column.dataIndex == 'coNoon2'
-          ">
+          <template
+            v-if="
+              column.dataIndex == 'coNight1' ||
+              column.dataIndex == 'coNight2' ||
+              column.dataIndex == 'coEarly1' ||
+              column.dataIndex == 'coEarly2' ||
+              column.dataIndex == 'coNoon1' ||
+              column.dataIndex == 'coNoon2'
+            "
+          >
             <div :style="{ color: Number(text) >= 0 && Number(text) <= 23 ? '#0ae715' : '#ff2313' }">{{ text }}</div>
           </template>
-          <template v-if="
-            column.dataIndex == 'tnight1' ||
-            column.dataIndex == 'tnight2' ||
-            column.dataIndex == 'tearly1' ||
-            column.dataIndex == 'tearly2' ||
-            column.dataIndex == 'tnoon1' ||
-            column.dataIndex == 'tnoon2'
-          ">
+          <template
+            v-if="
+              column.dataIndex == 'tnight1' ||
+              column.dataIndex == 'tnight2' ||
+              column.dataIndex == 'tearly1' ||
+              column.dataIndex == 'tearly2' ||
+              column.dataIndex == 'tnoon1' ||
+              column.dataIndex == 'tnoon2'
+            "
+          >
             <div :style="{ color: Number(text) >= 3 && Number(text) <= 25 ? '#0ae715' : '#ff2313' }">{{ text }}</div>
           </template>
-          <template v-if="
-            column.dataIndex == 'co2Night1' ||
-            column.dataIndex == 'co2Night2' ||
-            column.dataIndex == 'co2Early1' ||
-            column.dataIndex == 'co2Early2' ||
-            column.dataIndex == 'co2Noon1' ||
-            column.dataIndex == 'co2Noon2'
-          ">
-            <div :style="{ color: Number(text) >= 0.04 && Number(text) <= 0.1 ? '#0ae715' : '#ff2313' }">{{ text }}
-            </div>
+          <template
+            v-if="
+              column.dataIndex == 'co2Night1' ||
+              column.dataIndex == 'co2Night2' ||
+              column.dataIndex == 'co2Early1' ||
+              column.dataIndex == 'co2Early2' ||
+              column.dataIndex == 'co2Noon1' ||
+              column.dataIndex == 'co2Noon2'
+            "
+          >
+            <div :style="{ color: Number(text) >= 0.04 && Number(text) <= 0.1 ? '#0ae715' : '#ff2313' }">{{ text }} </div>
           </template>
-          <template v-if="
-            column.dataIndex == 'ch4Night1' ||
-            column.dataIndex == 'ch4Night2' ||
-            column.dataIndex == 'ch4Early1' ||
-            column.dataIndex == 'ch4Early2' ||
-            column.dataIndex == 'ch4Noon1' ||
-            column.dataIndex == 'ch4Noon2'
-          ">
+          <template
+            v-if="
+              column.dataIndex == 'ch4Night1' ||
+              column.dataIndex == 'ch4Night2' ||
+              column.dataIndex == 'ch4Early1' ||
+              column.dataIndex == 'ch4Early2' ||
+              column.dataIndex == 'ch4Noon1' ||
+              column.dataIndex == 'ch4Noon2'
+            "
+          >
             <div :style="{ color: Number(text) >= 0 && Number(text) <= 0.1 ? '#0ae715' : '#ff2313' }">{{ text }}</div>
           </template>
         </template>
@@ -131,446 +155,454 @@
       <BasicForm @register="registerForm" />
     </BasicModal>
 
-    <BasicModal @register="registerPageTypeModal" :showCancelBtn="false" :showOkBtn="false" :footer="null"
-      :defaultFullscreen="true" destroyOnClose>
-      <img style="width:100%;height:100%" :src="imgSrcView">
+    <BasicModal @register="registerPageTypeModal" :showCancelBtn="false" :showOkBtn="false" :footer="null" :defaultFullscreen="true" destroyOnClose>
+      <img style="width: 100%; height: 100%" :src="imgSrcView" />
     </BasicModal>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted, reactive } from 'vue';
-import { columns } from './gas-report.data';
-import { getGasAddressList, getList, expComReportByParam, reviewPass, getIsReviewPass, getAllUserInfo, exportReportByPoi, queryUserByRoleCode, gasServerImg } from './gas-report.api';
-import customHeader from '/@/components/vent/customHeader.vue';
-import { message } from 'ant-design-vue';
-import dayjs from 'dayjs';
-import { BasicModal, useModal } from '/@/components/Modal';
-import { BasicForm, useForm } from '/@/components/Form';
+  import { ref, onMounted, reactive } from 'vue';
+  import { columns } from './gas-report.data';
+  import {
+    getGasAddressList,
+    getList,
+    expComReportByParam,
+    reviewPass,
+    getIsReviewPass,
+    getAllUserInfo,
+    exportReportByPoi,
+    queryUserByRoleCode,
+    gasServerImg,
+  } from './gas-report.api';
+  import customHeader from '/@/components/vent/customHeader.vue';
+  import { message } from 'ant-design-vue';
+  import dayjs from 'dayjs';
+  import { BasicModal, useModal } from '/@/components/Modal';
+  import { BasicForm, useForm } from '/@/components/Form';
 
-let imgSrcView = ref('')
-let searchData = reactive({
-  reportTime: dayjs().format('YYYY-MM-DD'),
-  sbr: '',
-  strInstallPos: '',
-});
-let addressList = ref<any[]>([]); //上报地点下拉列表
-let pagination = reactive({
-  current: 1, // 当前页码
-  pageSize: 10, // 每页显示条数
-  total: 0, // 总条目数,后端返回
-  // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
-  showSizeChanger: true, // 是否可改变每页显示条数
-  pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
-});
-let tableData = ref<any[]>([]);
-const [registerPageTypeModal, pageTypeModalCtx] = useModal();
-const [registerModal, { openModal }] = useModal();
+  let imgSrcView = ref('');
+  let searchData = reactive({
+    reportTime: dayjs().format('YYYY-MM-DD'),
+    sbr: '',
+    strInstallPos: '',
+  });
+  let addressList = ref<any[]>([]); //上报地点下拉列表
+  let pagination = reactive({
+    current: 1, // 当前页码
+    pageSize: 10, // 每页显示条数
+    total: 0, // 总条目数,后端返回
+    // showTotal: (total, range) => `${range[0]}-${range[1]} 条,总共 ${total} 条`, // 分页右下角显示信息
+    showSizeChanger: true, // 是否可改变每页显示条数
+    pageSizeOptions: ['10', '20', '50'], // 可选的每页显示条数
+  });
+  let tableData = ref<any[]>([]);
+  const [registerPageTypeModal, pageTypeModalCtx] = useModal();
+  const [registerModal, { openModal }] = useModal();
 
-//打开瓦斯巡检预览弹窗
-function imgViewClick(record) {
-  imgSrcView.value = ''
-  pageTypeModalCtx.openModal()
-  getImage(record)
-}
-//获取瓦斯巡检图片
-function getImage(record) {
-  console.log(record, '000===')
-  let params
-  switch (record.dataIndex) {
-    case 'night1':
-      params = {
-        reportdate: record.record.reportTime,
-        checkpath: record.record.strInstallPos,
-        order: '夜班',
-        checkorder: 1,
-      }
-      getImageList(params)
-      break;
-    case 'night2':
-      params = {
-        reportdate: record.record.reportTime,
-        checkpath: record.record.strInstallPos,
-        order: '夜班',
-        checkorder: 2,
-      }
-      getImageList(params)
-      break;
-    case 'early1':
-      params = {
-        reportdate: record.record.reportTime,
-        checkpath: record.record.strInstallPos,
-        order: '早班',
-        checkorder: 1,
-      }
-      getImageList(params)
-      break;
-    case 'early2':
-      params = {
-        reportdate: record.record.reportTime,
-        checkpath: record.record.strInstallPos,
-        order: '早班',
-        checkorder: 2,
-      }
-      getImageList(params)
-      break;
-    case 'noon1':
-      params = {
-        reportdate: record.record.reportTime,
-        checkpath: record.record.strInstallPos,
-        order: '中班',
-        checkorder: 1,
-      }
-      getImageList(params)
-      break;
-    case 'noon2':
-      params = {
-        reportdate: record.record.reportTime,
-        checkpath: record.record.strInstallPos,
-        order: '中班',
-        checkorder: 2,
-      }
-      getImageList(params)
-      break;
+  //打开瓦斯巡检预览弹窗
+  function imgViewClick(record) {
+    imgSrcView.value = '';
+    pageTypeModalCtx.openModal();
+    getImage(record);
+  }
+  //获取瓦斯巡检图片
+  function getImage(record) {
+    console.log(record, '000===');
+    let params;
+    switch (record.dataIndex) {
+      case 'night1':
+        params = {
+          reportdate: record.record.reportTime,
+          checkpath: record.record.strInstallPos,
+          order: '夜班',
+          checkorder: 1,
+        };
+        getImageList(params);
+        break;
+      case 'night2':
+        params = {
+          reportdate: record.record.reportTime,
+          checkpath: record.record.strInstallPos,
+          order: '夜班',
+          checkorder: 2,
+        };
+        getImageList(params);
+        break;
+      case 'early1':
+        params = {
+          reportdate: record.record.reportTime,
+          checkpath: record.record.strInstallPos,
+          order: '早班',
+          checkorder: 1,
+        };
+        getImageList(params);
+        break;
+      case 'early2':
+        params = {
+          reportdate: record.record.reportTime,
+          checkpath: record.record.strInstallPos,
+          order: '早班',
+          checkorder: 2,
+        };
+        getImageList(params);
+        break;
+      case 'noon1':
+        params = {
+          reportdate: record.record.reportTime,
+          checkpath: record.record.strInstallPos,
+          order: '中班',
+          checkorder: 1,
+        };
+        getImageList(params);
+        break;
+      case 'noon2':
+        params = {
+          reportdate: record.record.reportTime,
+          checkpath: record.record.strInstallPos,
+          order: '中班',
+          checkorder: 2,
+        };
+        getImageList(params);
+        break;
+    }
   }
-}
-
-
-async function getImageList(params) {
-  let res = await gasServerImg(params)
-  const img = new Blob(res, { type: 'image/png' }); // 创建Blob对象
-  imgSrcView.value = URL.createObjectURL(img); // 创建可访问的URL
-}
-//获取日报列表数据
-async function getTableList() {
-  let res = await getList({ pageNo: pagination.current, pageSize: pagination.pageSize, ...searchData });
-  res.records.forEach((el) => {
-    el.jwSdzNight1 = el.jwSdzNight1 || '-';
-    el.jwSdzNight2 = el.jwSdzNight2 || '-';
-    el.jwSdzEarly1 = el.jwSdzEarly1 || '-';
-    el.jwSdzEarly2 = el.jwSdzEarly2 || '-';
-    el.jwSdzNoon1 = el.jwSdzNoon1 || '-';
-    el.jwSdzNoon2 = el.jwSdzNoon2 || '-';
-  });
-  tableData.value = res.records;
-  pagination.total = res.total;
-}
-//查询
-function getSearch() {
-  pagination.current = 1;
-  getTableList();
-}
-//重置
-function onReset() {
-  pagination.current = 1;
-  searchData.reportTime = '';
-  searchData.strInstallPos = '';
-  searchData.sbr = '';
-  getTableList();
-}
-//分页切换
-function pageChange(val) {
-  pagination.current = val.current;
-  pagination.pageSize = val.pageSize;
-  getTableList();
-}
 
-//获取安装位置下拉选项
-async function getSelectList() {
-  let res = await getGasAddressList({ coalseam: '', devicekind: 'gasDayReport' });
-  if (res.length != 0) {
-    addressList.value = res.map((el) => {
-      return { label: el.strinstallpos, value: el.strinstallpos }
+  async function getImageList(params) {
+    let res = await gasServerImg(params);
+    const img = new Blob(res, { type: 'image/png' }); // 创建Blob对象
+    imgSrcView.value = URL.createObjectURL(img); // 创建可访问的URL
+  }
+  //获取日报列表数据
+  async function getTableList() {
+    let res = await getList({ pageNo: pagination.current, pageSize: pagination.pageSize, ...searchData });
+    res.records.forEach((el) => {
+      el.jwSdzNight1 = el.jwSdzNight1 || '-';
+      el.jwSdzNight2 = el.jwSdzNight2 || '-';
+      el.jwSdzEarly1 = el.jwSdzEarly1 || '-';
+      el.jwSdzEarly2 = el.jwSdzEarly2 || '-';
+      el.jwSdzNoon1 = el.jwSdzNoon1 || '-';
+      el.jwSdzNoon2 = el.jwSdzNoon2 || '-';
     });
+    tableData.value = res.records;
+    pagination.total = res.total;
   }
-}
-//导出报表
-async function getExport() {
-  if (getTs()) {
-    message.warning('数据异常!');
-  } else {
-    if (searchData.reportTime) {
-      let data = await getIsReviewPass({ reportTime: searchData.reportTime });
-      if (data == '已审核通过!') {
-        let res = await expComReportByParam({ tempName: 'wsrb', reportTime: searchData.reportTime });
-        let filename = searchData.reportTime + '.xlsx';
-        downFilePublic(res, filename);
-      }
+  //查询
+  function getSearch() {
+    pagination.current = 1;
+    getTableList();
+  }
+  //重置
+  function onReset() {
+    pagination.current = 1;
+    searchData.reportTime = '';
+    searchData.strInstallPos = '';
+    searchData.sbr = '';
+    getTableList();
+  }
+  //分页切换
+  function pageChange(val) {
+    pagination.current = val.current;
+    pagination.pageSize = val.pageSize;
+    getTableList();
+  }
+
+  //获取安装位置下拉选项
+  async function getSelectList() {
+    let res = await getGasAddressList({ coalseam: '', devicekind: 'gasDayReport' });
+    if (res.length != 0) {
+      addressList.value = res.map((el) => {
+        return { label: el.strinstallpos, value: el.strinstallpos };
+      });
+    }
+  }
+  //导出报表
+  async function getExport() {
+    if (getTs()) {
+      message.warning('数据异常!');
     } else {
+      if (searchData.reportTime) {
+        let data = await getIsReviewPass({ reportTime: searchData.reportTime });
+        if (data == '已审核通过!') {
+          let res = await expComReportByParam({ tempName: 'wsrb', reportTime: searchData.reportTime });
+          let filename = searchData.reportTime + '.xlsx';
+          downFilePublic(res, filename);
+        }
+      } else {
+        message.warning('请选择需要导出数据的填报日期!');
+      }
+    }
+  }
+  //导出三对照报表
+  // async function getExport1() {
+  //   if (searchData.reportTime) {
+  //     let res = await expComReportByParam({ tempName: 'wssdz', reportTime: searchData.reportTime });
+  //     let filename = searchData.reportTime + '.xlsx';
+  //     downFilePublic(res, filename);
+  //   } else {
+  //     message.warning('请选择需要导出数据的填报日期!');
+  //   }
+  // }
+  //导出瓦斯检查小票
+  async function getExport2() {
+    if (searchData.reportTime) {
+      openModal();
+    } else if (!searchData.reportTime) {
       message.warning('请选择需要导出数据的填报日期!');
+    } else if (!searchData.sbr) {
+      message.warning('请输入检查工名称!');
     }
   }
-}
-//导出三对照报表
-// async function getExport1() {
-//   if (searchData.reportTime) {
-//     let res = await expComReportByParam({ tempName: 'wssdz', reportTime: searchData.reportTime });
-//     let filename = searchData.reportTime + '.xlsx';
-//     downFilePublic(res, filename);
-//   } else {
-//     message.warning('请选择需要导出数据的填报日期!');
-//   }
-// }
-//导出瓦斯检查小票
-async function getExport2() {
-  if (searchData.reportTime) {
-    openModal();
-  } else if (!searchData.reportTime) {
-    message.warning('请选择需要导出数据的填报日期!');
-  } else if (!searchData.sbr) {
-    message.warning('请输入检查工名称!');
+
+  function getTs() {
+    let param = true;
+    tableData.value.forEach((el) => {
+      if (
+        Number(el.o2Night1) >= 18 &&
+        Number(el.o2Night1) <= 20.9 &&
+        Number(el.o2Night2) >= 18 &&
+        Number(el.o2Night2) <= 20.9 &&
+        Number(el.o2Early1) >= 18 &&
+        Number(el.o2Early1) <= 20.9 &&
+        Number(el.o2Early2) >= 18 &&
+        Number(el.o2Early2) <= 20.9 &&
+        Number(el.o2Noon1) >= 18 &&
+        Number(el.o2Noon1) <= 20.9 &&
+        Number(el.o2Noon2) >= 18 &&
+        Number(el.o2Noon2) <= 20.9
+      ) {
+        param = false;
+      } else if (
+        Number(el.coNight1) >= 0 &&
+        Number(el.coNight1) <= 23 &&
+        Number(el.coNight2) >= 0 &&
+        Number(el.coNight2) <= 23 &&
+        Number(el.coEarly1) >= 0 &&
+        Number(el.coEarly1) <= 23 &&
+        Number(el.coEarly2) >= 0 &&
+        Number(el.coEarly2) <= 23 &&
+        Number(el.coNoon1) >= 0 &&
+        Number(el.coNoon1) <= 23 &&
+        Number(el.coNoon2) >= 0 &&
+        Number(el.coNoon2) <= 23
+      ) {
+        param = false;
+      } else if (
+        Number(el.co2Night1) >= 0.04 &&
+        Number(el.co2Night1) <= 0.1 &&
+        Number(el.co2Night2) >= 0.04 &&
+        Number(el.co2Night2) <= 0.1 &&
+        Number(el.co2Early1) >= 0.04 &&
+        Number(el.co2Early1) <= 0.1 &&
+        Number(el.co2Early2) >= 0.04 &&
+        Number(el.co2Early2) <= 0.1 &&
+        Number(el.co2Noon1) >= 0.04 &&
+        Number(el.co2Noon1) <= 0.1 &&
+        Number(el.co2Noon2) >= 0.04 &&
+        Number(el.co2Noon2) <= 0.1
+      ) {
+        param = false;
+      } else if (
+        Number(el.tnight1) >= 3 &&
+        Number(el.tnight1) <= 25 &&
+        Number(el.tnight2) >= 3 &&
+        Number(el.tnight2) <= 25 &&
+        Number(el.tearly1) >= 3 &&
+        Number(el.tearly1) <= 25 &&
+        Number(el.tearly2) >= 3 &&
+        Number(el.tearly2) <= 25 &&
+        Number(el.tnoon1) >= 3 &&
+        Number(el.tnoon1) <= 25 &&
+        Number(el.tnoon2) >= 3 &&
+        Number(el.tnoon2) <= 25
+      ) {
+        param = false;
+      } else if (
+        Number(el.ch4Night1) >= 0 &&
+        Number(el.ch4Night1) <= 0.1 &&
+        Number(el.ch4Night2) >= 0 &&
+        Number(el.ch4Night2) <= 0.1 &&
+        Number(el.ch4Early1) >= 0 &&
+        Number(el.ch4Early1) <= 0.1 &&
+        Number(el.ch4Early2) >= 0 &&
+        Number(el.ch4Early2) <= 0.1 &&
+        Number(el.ch4Noon1) >= 0 &&
+        Number(el.ch4Noon1) <= 0.1 &&
+        Number(el.ch4Noon2) >= 0 &&
+        Number(el.ch4Noon2) <= 0.1
+      ) {
+        param = false;
+      } else {
+        param = true;
+        return;
+      }
+    });
+    return param;
   }
-}
 
-function getTs() {
-  let param = true;
-  tableData.value.forEach((el) => {
-    if (
-      Number(el.o2Night1) >= 18 &&
-      Number(el.o2Night1) <= 20.9 &&
-      Number(el.o2Night2) >= 18 &&
-      Number(el.o2Night2) <= 20.9 &&
-      Number(el.o2Early1) >= 18 &&
-      Number(el.o2Early1) <= 20.9 &&
-      Number(el.o2Early2) >= 18 &&
-      Number(el.o2Early2) <= 20.9 &&
-      Number(el.o2Noon1) >= 18 &&
-      Number(el.o2Noon1) <= 20.9 &&
-      Number(el.o2Noon2) >= 18 &&
-      Number(el.o2Noon2) <= 20.9
-    ) {
-      param = false;
-    } else if (
-      Number(el.coNight1) >= 0 &&
-      Number(el.coNight1) <= 23 &&
-      Number(el.coNight2) >= 0 &&
-      Number(el.coNight2) <= 23 &&
-      Number(el.coEarly1) >= 0 &&
-      Number(el.coEarly1) <= 23 &&
-      Number(el.coEarly2) >= 0 &&
-      Number(el.coEarly2) <= 23 &&
-      Number(el.coNoon1) >= 0 &&
-      Number(el.coNoon1) <= 23 &&
-      Number(el.coNoon2) >= 0 &&
-      Number(el.coNoon2) <= 23
-    ) {
-      param = false;
-    } else if (
-      Number(el.co2Night1) >= 0.04 &&
-      Number(el.co2Night1) <= 0.1 &&
-      Number(el.co2Night2) >= 0.04 &&
-      Number(el.co2Night2) <= 0.1 &&
-      Number(el.co2Early1) >= 0.04 &&
-      Number(el.co2Early1) <= 0.1 &&
-      Number(el.co2Early2) >= 0.04 &&
-      Number(el.co2Early2) <= 0.1 &&
-      Number(el.co2Noon1) >= 0.04 &&
-      Number(el.co2Noon1) <= 0.1 &&
-      Number(el.co2Noon2) >= 0.04 &&
-      Number(el.co2Noon2) <= 0.1
-    ) {
-      param = false;
-    } else if (
-      Number(el.tnight1) >= 3 &&
-      Number(el.tnight1) <= 25 &&
-      Number(el.tnight2) >= 3 &&
-      Number(el.tnight2) <= 25 &&
-      Number(el.tearly1) >= 3 &&
-      Number(el.tearly1) <= 25 &&
-      Number(el.tearly2) >= 3 &&
-      Number(el.tearly2) <= 25 &&
-      Number(el.tnoon1) >= 3 &&
-      Number(el.tnoon1) <= 25 &&
-      Number(el.tnoon2) >= 3 &&
-      Number(el.tnoon2) <= 25
-    ) {
-      param = false;
-    } else if (
-      Number(el.ch4Night1) >= 0 &&
-      Number(el.ch4Night1) <= 0.1 &&
-      Number(el.ch4Night2) >= 0 &&
-      Number(el.ch4Night2) <= 0.1 &&
-      Number(el.ch4Early1) >= 0 &&
-      Number(el.ch4Early1) <= 0.1 &&
-      Number(el.ch4Early2) >= 0 &&
-      Number(el.ch4Early2) <= 0.1 &&
-      Number(el.ch4Noon1) >= 0 &&
-      Number(el.ch4Noon1) <= 0.1 &&
-      Number(el.ch4Noon2) >= 0 &&
-      Number(el.ch4Noon2) <= 0.1
-    ) {
-      param = false;
+  //审核通过
+  async function getPassSh() {
+    if (getTs()) {
+      message.warning('数据异常!');
     } else {
-      param = true;
-      return;
-    }
-  });
-  return param;
-}
-
-//审核通过
-async function getPassSh() {
-  if (getTs()) {
-    message.warning('数据异常!');
-  } else {
-    let res = await reviewPass({ reportTime: searchData.reportTime });
-    if (res) {
-      getTableList();
+      let res = await reviewPass({ reportTime: searchData.reportTime });
+      if (res) {
+        getTableList();
+      }
     }
   }
-}
 
-// 下载公用方法
-function downFilePublic(content, fileName) {
-  const blob = new Blob([content], { type: 'application/xlsx;charset=UTF-8' }); // 构造一个blob对象来处理数据
-  // 对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
-  // IE10以上支持blob但是依然不支持download
-  if ('download' in document.createElement('a')) {
-    // 支持a标签download的浏览器
-    const link = document.createElement('a'); // 创建a标签
-    link.download = fileName; // a标签添加属性
-    link.style.display = 'none';
-    link.href = URL.createObjectURL(blob);
-    document.body.appendChild(link);
-    link.click(); // 执行下载
-    URL.revokeObjectURL(link.href); // 释放url
-    document.body.removeChild(link); // 释放标签
-  } else {
-    // 其他浏览器
-    navigator.msSaveBlob(blob, fileName);
+  // 下载公用方法
+  function downFilePublic(content, fileName) {
+    const blob = new Blob([content], { type: 'application/xlsx;charset=UTF-8' }); // 构造一个blob对象来处理数据
+    // 对于<a>标签,只有 Firefox 和 Chrome(内核) 支持 download 属性
+    // IE10以上支持blob但是依然不支持download
+    if ('download' in document.createElement('a')) {
+      // 支持a标签download的浏览器
+      const link = document.createElement('a'); // 创建a标签
+      link.download = fileName; // a标签添加属性
+      link.style.display = 'none';
+      link.href = URL.createObjectURL(blob);
+      document.body.appendChild(link);
+      link.click(); // 执行下载
+      URL.revokeObjectURL(link.href); // 释放url
+      document.body.removeChild(link); // 释放标签
+    } else {
+      // 其他浏览器
+      navigator.msSaveBlob(blob, fileName);
+    }
   }
-}
-//导出瓦斯班报表
-async function handleMenuClick(val) {
-  if (searchData.reportTime) {
-    let res = await expComReportByParam({ tempName: 'wsrbshb', reportTime: searchData.reportTime });
-    let filename = searchData.reportTime + '.xlsx';
-    downFilePublic(res, filename);
-  } else {
-    message.warning('请选择需要导出数据的填报日期!');
+  //导出瓦斯班报表
+  async function handleMenuClick(val) {
+    if (searchData.reportTime) {
+      let res = await expComReportByParam({ tempName: 'wsrbshb', reportTime: searchData.reportTime });
+      let filename = searchData.reportTime + '.xlsx';
+      downFilePublic(res, filename);
+    } else {
+      message.warning('请选择需要导出数据的填报日期!');
+    }
   }
-}
-const [registerForm, { validate, setFieldsValue }] = useForm({
-  schemas: [
-    {
-      label: '检查工',
-      field: 'checkName',
-      component: 'ApiSelect',
-      required: true,
-      show: false,
-    },
-    {
-      label: '交班瓦检员',
-      field: 'agoCheckPerson',
-      component: 'ApiSelect',
-      required: true,
-      componentProps: {
-        api: queryUserByRoleCode,
-        params: { roleCode: 'gasCheck' },
-        labelField: 'realname',
-        valueField: 'username',
-        showSearch: true,
+  const [registerForm, { validate, setFieldsValue }] = useForm({
+    schemas: [
+      {
+        label: '检查工',
+        field: 'checkName',
+        component: 'ApiSelect',
+        required: true,
+        show: false,
       },
-    },
-    {
-      label: '当班瓦检员',
-      field: 'nowCheckPerson',
-      component: 'ApiSelect',
-      required: true,
-      componentProps: {
-        api: queryUserByRoleCode,
-        params: { roleCode: 'gasCheck' },
-        labelField: 'realname',
-        valueField: 'username',
-        showSearch: true,
-        onChange(__, { label }) {
-          setFieldsValue({
-            checkName: label,
-          });
+      {
+        label: '交班瓦检员',
+        field: 'agoCheckPerson',
+        component: 'ApiSelect',
+        required: true,
+        componentProps: {
+          api: queryUserByRoleCode,
+          params: { roleCode: 'gasCheck' },
+          labelField: 'realname',
+          valueField: 'username',
+          showSearch: true,
         },
       },
-    },
-    {
-      label: '接班瓦检员',
-      field: 'nextCheckPerson',
-      component: 'ApiSelect',
-      required: true,
-      componentProps: {
-        api: queryUserByRoleCode,
-        params: { roleCode: 'gasCheck' },
-        labelField: 'realname',
-        valueField: 'username',
-        showSearch: true,
+      {
+        label: '当班瓦检员',
+        field: 'nowCheckPerson',
+        component: 'ApiSelect',
+        required: true,
+        componentProps: {
+          api: queryUserByRoleCode,
+          params: { roleCode: 'gasCheck' },
+          labelField: 'realname',
+          valueField: 'username',
+          showSearch: true,
+          onChange(__, { label }) {
+            setFieldsValue({
+              checkName: label,
+            });
+          },
+        },
+      },
+      {
+        label: '接班瓦检员',
+        field: 'nextCheckPerson',
+        component: 'ApiSelect',
+        required: true,
+        componentProps: {
+          api: queryUserByRoleCode,
+          params: { roleCode: 'gasCheck' },
+          labelField: 'realname',
+          valueField: 'username',
+          showSearch: true,
+        },
       },
-    },
-  ],
-  labelWidth: 100,
-  showActionButtonGroup: false,
-});
+    ],
+    labelWidth: 100,
+    showActionButtonGroup: false,
+  });
 
-/** 导出瓦斯检查小票 */
-async function submitHandler() {
-  const params = await validate();
-  const res = await exportReportByPoi({ tempName: 'wsjcxp', reportTime: searchData.reportTime, ...params });
-  const filename = searchData.reportTime + '.xlsx';
-  downFilePublic(res, filename);
-}
+  /** 导出瓦斯检查小票 */
+  async function submitHandler() {
+    const params = await validate();
+    const res = await exportReportByPoi({ tempName: 'wsjcxp', reportTime: searchData.reportTime, ...params });
+    const filename = searchData.reportTime + '.xlsx';
+    downFilePublic(res, filename);
+  }
 
-onMounted(() => {
-  getSelectList();
-  getTableList();
-});
+  onMounted(() => {
+    getSelectList();
+    getTableList();
+  });
 </script>
 
 <style lang="less" scoped>
-@import '/@/design/theme.less';
+  @import '/@/design/theme.less';
 
-.gasReport {
-  width: 100%;
-  height: 100%;
-  padding: 80px 10px 15px 10px;
-  box-sizing: border-box;
-  position: relative;
+  .gasReport {
+    width: 100%;
+    height: 100%;
+    padding: 80px 10px 15px 10px;
+    box-sizing: border-box;
+    position: relative;
 
-  .search-area {
-    margin: 20px 0px;
+    .search-area {
+      margin: 20px 0px;
 
-    .area-item {
-      display: flex;
-      align-items: center;
+      .area-item {
+        display: flex;
+        align-items: center;
 
-      .item-text {
-        color: #fff;
+        .item-text {
+          color: #fff;
+        }
       }
     }
-  }
 
-  .zxm-picker,
-  .zxm-input {
-    border: 1px solid var(--vent-form-item-border) !important;
-    background-color: #ffffff00 !important;
-    color: #fff !important;
-  }
+    .zxm-picker,
+    .zxm-input {
+      border: 1px solid var(--vent-form-item-border) !important;
+      background-color: #ffffff00 !important;
+      color: #fff !important;
+    }
 
-  .img-view {
-    color: #1ff5e3;
+    .img-view {
+      color: #1ff5e3;
+    }
   }
-}
 
-:deep(.zxm-table-thead > tr > th:last-child) {
-  border-right: 1px solid #91e9fe !important;
-}
+  :deep(.zxm-table-thead > tr > th:last-child) {
+    border-right: 1px solid #91e9fe !important;
+  }
 
-:deep(.zxm-picker-input > input) {
-  color: #fff;
-}
+  :deep(.zxm-picker-input > input) {
+    color: #fff;
+  }
 
-:deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
-  border: 1px solid var(--vent-form-item-border) !important;
-  background-color: #ffffff00 !important;
-}
+  :deep(.zxm-select:not(.zxm-select-customize-input) .zxm-select-selector) {
+    border: 1px solid var(--vent-form-item-border) !important;
+    background-color: #ffffff00 !important;
+  }
 
-:deep(.zxm-select-selection-item) {
-  color: #fff !important;
-}
+  :deep(.zxm-select-selection-item) {
+    color: #fff !important;
+  }
 </style>

+ 1 - 1
src/views/vent/home/clique/components/3Dmap/3dMap.ts

@@ -642,7 +642,7 @@ class earthtMap {
     const geometry = new THREE.PlaneGeometry(15.0, 15.0);
     const texture = new THREE.TextureLoader().load('/texture/earth.jpg');
     const bumpTexture = new THREE.TextureLoader().load('/texture/earth.jpg');
-    texture.encoding = THREE.sRGBEncoding;
+    texture.encoding = THREE.colorSpace;
     const material = new THREE.MeshPhongMaterial({
       map: texture, // 贴图
       bumpMap: bumpTexture,

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

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

+ 20 - 10
src/views/vent/home/configurable/components/ModuleCommonDual.vue

@@ -149,16 +149,26 @@
       background: linear-gradient(to top, #2bafc6 0%, rgba(44, 255, 221, 0.1) 50%, rgba(44, 255, 221, 0) 90%);
     }
   }
-  // @{theme-deepblue} {
-  //   .module-common-dual-longer {
-  //     :deep(.box1-top) {
-  //       --image-box1-top: url('/@/assets/images/themify/deepblue/vent/border/box2-top-long.png');
-  //     }
-  //     :deep(.box1-bottom) {
-  //       --image-box1-bottom: none;
-  //     }
-  //   }
-  // }
+  @{theme-green} {
+    .module-common-dual-longer {
+      :deep(.box1-top) {
+        --image-box1-top: url('/@/assets/images/themify/green/vent/border/box-top.png');
+      }
+      :deep(.box1-bottom) {
+        --image-box1-bottom: url('/@/assets/images/themify/green/vent/border/box-bottom.png');
+      }
+    }
+  }
+  @{theme-deepblue} {
+    .module-common-dual-longer {
+      :deep(.box1-top) {
+        --image-box1-top: url('/@/assets/images/themify/deepblue/vent/border/box2-top-long.png');
+      }
+      :deep(.box1-bottom) {
+        --image-box1-bottom: none;
+      }
+    }
+  }
   .module-common-dual-longer {
     :deep(.box1-top) {
       --image-box1-top: url('/@/assets/images/vent/box-top-bg.png');

+ 62 - 41
src/views/vent/home/configurable/configurable.api.ts

@@ -16,7 +16,7 @@ enum Api {
   getAlarmRecord = '/ventanaly-device/safety/ventanalyAlarmLog/sysLinkDevAlarmLog',
   getTotal = '/safety/ventanalyAlarmLog/total',
   sysTypeWarnList = '/safety/ventanalyAlarmLog/sysTypeWarn',
-  getDisasterProportion = '/safety/ventanalyAlarmLog/getDisasterProportion'
+  getDisasterProportion = '/safety/ventanalyAlarmLog/getDisasterProportion',
 }
 
 // 搞这个缓存是由于:目前代码上的设计是多个模块发出多次请求,每个模块自己负责消费前者的响应。
@@ -125,6 +125,27 @@ export const list = (params) => {
         }
       });
     }
+    if (res.safetymonitor) {
+      const { sysOrgCode } = useGlobSetting();
+      // 沙坪
+      if (sysOrgCode === 'jsnyspmy') {
+        res.safetymonitor = _.sortBy(res.safetymonitor, (e) => {
+          const map = new Map([
+            ['1960160466651189249', 1],
+            ['1960160465543892994', 2],
+            ['1960160465376120833', 3],
+            ['1960160466168844289', 4],
+            ['1960160465736830977', 5],
+            ['1960160466026237954', 6],
+            ['1960160407146598402', 7],
+          ]);
+
+          const inx = map.get(e.deviceID) || 9999;
+
+          return inx;
+        });
+      }
+    }
 
     return res;
   });
@@ -398,26 +419,26 @@ export const getDisasterProportion = (params) => {
 //多灾融合预警
 function getLevelNum() {
   return new Promise(async (resolve) => {
-    const list = {}
+    const list: Record<string, any> = {};
     const typeArr = ['fire', 'dust', 'vent', 'gas'];
     for (let i = 0; i < typeArr.length; i++) {
       const type = typeArr[i];
       const result = await sysTypeWarnList({ type });
       if (type == 'fire') {
-        list.fire = result.length || 0
+        list.fire = result.length || 0;
       } else if (type == 'dust') {
-        list.dust = result.length || 0
+        list.dust = result.length || 0;
       } else if (type == 'vent') {
-        list.vent = result.length || 0
+        list.vent = result.length || 0;
       } else if (type == 'gas') {
-        list.gas = result.length || 0
+        list.gas = result.length || 0;
       }
     }
     resolve(list);
   });
 }
 export const getTotal = (params) => {
-  const { sysOrgCode, sysDataType } = useGlobSetting();
+  const { sysDataType } = useGlobSetting();
 
   const key = `${Api.getTotal}?${JSON.stringify(params)}`;
   if (!cache.has(key)) {
@@ -429,25 +450,25 @@ export const getTotal = (params) => {
     );
   }
   return (cache.get(key) as Promise<any>).then(async (res) => {
-    console.log(res, '多灾融合预警数据')
+    console.log(res, '多灾融合预警数据');
 
     let dataVent = await getLevelNum()
     const levelsList = [
       {
-        name: "报警",
-        value: 0
+        name: '报警',
+        value: 0,
       },
       {
-        name: "重大风险",
-        value: 0
+        name: '重大风险',
+        value: 0,
       },
       {
-        name: "较大风险",
-        value: 0
+        name: '较大风险',
+        value: 0,
       },
       {
-        name: "一般风险",
-        value: 0
+        name: '一般风险',
+        value: 0,
       },
       {
         name: "低风险",
@@ -461,27 +482,27 @@ export const getTotal = (params) => {
           ventJf: res.ventInfo.zongjinfeng,
           ventXf: res.ventInfo.xufengliang,
           ventHf: res.ventInfo.zonghuifeng,
-        }
+        };
         res.ventData = [
           {
-            name: "报警",
-            value: res.info.sysInfo.ventS.levels.alarm
+            name: '报警',
+            value: res.info.sysInfo.ventS.levels.alarm,
           },
           {
-            name: "重大风险",
-            value: res.info.sysInfo.ventS.levels.red
+            name: '重大风险',
+            value: res.info.sysInfo.ventS.levels.red,
           },
           {
-            name: "较大风险",
-            value: res.info.sysInfo.ventS.levels.orange
+            name: '较大风险',
+            value: res.info.sysInfo.ventS.levels.orange,
           },
           {
-            name: "一般风险",
-            value: res.info.sysInfo.ventS.levels.yellow
+            name: '一般风险',
+            value: res.info.sysInfo.ventS.levels.yellow,
           },
           {
-            name: "低风险",
-            value: dataVent.vent ? dataVent.vent : res.info.sysInfo.ventS.levels.blue
+            name: '低风险',
+            value: dataVent.vent ? dataVent.vent : res.info.sysInfo.ventS.levels.blue,
           },
         ];
 
@@ -491,29 +512,29 @@ export const getTotal = (params) => {
           ventJf: res.ventInfo.totalIntM3,
           ventXf: res.ventInfo.xufengliang,
           ventHf: res.ventInfo.totalRetM3,
-        }
-        res.ventData = levelsList
+        };
+        res.ventData = levelsList;
         break;
       default:
         res.ventWarn = {
           ventJf: res.ventInfo.totalIntM3,
           ventXf: res.ventInfo.xufengliang,
           ventHf: res.ventInfo.totalRetM3,
-        }
-        res.ventData = levelsList
+        };
+        res.ventData = levelsList;
     }
     //设备监测预警数据
-    res.deviceWarn = reactive({})
-    Object.keys(res.info.devicekindInfo).forEach((el, index) => {
+    res.deviceWarn = reactive({});
+    Object.keys(res.info.devicekindInfo).forEach((el) => {
       res.deviceWarn[`${el}_all`] = res.info.devicekindInfo[el].totalcount;
       res.deviceWarn[`${el}_warn`] = res.info.devicekindInfo[el].count;
       res.deviceWarn[`${el}_close`] = res.info.devicekindInfo[el].netstatus;
-    })
+    });
     //瓦斯监测预警数据
-    res.gasData = reactive({})
-    res.gasData.safety_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.gasNumber, 0)
-    res.gasData.gas_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.pumpNumber, 0)
-    res.gasData.monitorData = res.info.sysInfo.gasS.devices.map(el => {
+    res.gasData = reactive({});
+    res.gasData.safety_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.gasNumber, 0);
+    res.gasData.gas_sum = res.info.sysInfo.gasS.devices.reduce((a, b) => a + b.pumpNumber, 0);
+    res.gasData.monitorData = res.info.sysInfo.gasS.devices.map((el) => {
       return {
         label: el.systemname,
         value: el.gasNumber,
@@ -526,7 +547,7 @@ export const getTotal = (params) => {
     res.fireInfos.dataOn = []
 
     if (res.bundletubeInfo && res.bundletubeInfo.msgTxt.length != 0 && res.bundletubeInfo.msgTxt[0].datalist.length != 0) {
-      res.bundletubeInfo.msgTxt[0].datalist.forEach((el, ind) => {
+      res.bundletubeInfo.msgTxt[0].datalist.forEach((el) => {
         res.fireInfos.dataOn.push({
           warnLevel: el.syswarnLevel_str,
           smokeJd: el.syswarnLevel_des,
@@ -534,7 +555,7 @@ export const getTotal = (params) => {
         });
       });
     } else {
-      res.fireInfos.dataOn = []
+      res.fireInfos.dataOn = [];
     }
     res.fireInfos.tempVal = res.info.sysInfo.fireS.summaryInfo
       ? res.info.sysInfo.fireS.summaryInfo.external.temperature && res.info.sysInfo.fireS.summaryInfo.external.temperature.maxlevel == '0'
@@ -613,7 +634,7 @@ export const getElectroData = (params) => {
  
   res.tempData=res?.datalist?.map((el,index)=>{
     return {
-      areaName:el.readData.areaName || `分区${index+1}`,
+      areaName:el.readData.areaName,
       tempStart:el.readData.tempStart,
       tempStop:el.readData.tempStop
     }

+ 5 - 1
src/views/vent/home/configurable/dust.vue

@@ -109,7 +109,11 @@
     font-family: 'douyuFont';
     src: url('../../../../assets/font/douyuFont.otf');
   }
-
+  @{theme-green} {
+    .company-home {
+      --image-modal-top: url('@/assets/images/themify/green/vent/vent-header1.png');
+    }
+  }
   @{theme-deepblue} {
     .company-home {
       --image-modal-top: url('@/assets/images/themify/deepblue/vent/home/modal-top.png');

+ 5 - 0
src/views/vent/home/configurable/fire.vue

@@ -110,6 +110,11 @@
     src: url('../../../../assets/font/douyuFont.otf');
   }
 
+  @{theme-green} {
+    .company-home {
+      --image-modal-top: url('@/assets/images/themify/green/vent/vent-header1.png');
+    }
+  }
   @{theme-deepblue} {
     .company-home {
       --image-modal-top: url('@/assets/images/themify/deepblue/vent/home/modal-top.png');

+ 8 - 7
src/views/vent/home/configurable/ventSDG.vue

@@ -21,7 +21,7 @@
     </div> -->
     </div>
     <!-- 如果是有 deviceType、type 等 query,认为是详情页,不需要展示普通模块,只需要模型 -->
-    <CustomHeader v-if="!route.query.embed">三道沟煤矿均压综采面智能监测与动态调控</CustomHeader>
+    <CustomHeader v-if="!route.query.embed">{{ mainTitle }}</CustomHeader>
     <!-- <a class="ant-dropdown-link module-dropdown" @click.prevent="showBar = !showBar">
         全矿井通风检测
         <CaretDownOutlined />
@@ -104,14 +104,14 @@
   import { list } from './configurable.api';
   import { useRoute } from 'vue-router';
   import { useGlobSetting } from '/@/hooks/setting';
-  import { testConfigSDG } from './configurable.data.wz';
+  // import { testConfigSDG } from './configurable.data.wz';
 
-  const { sysDataType = 'monitor', title = '三道沟煤矿均压综采面智能监测与动态调控', sysOrgCode } = useGlobSetting();
+  const { /* sysDataType = 'monitor', */ title = '三道沟煤矿均压综采面智能监测与动态调控', sysOrgCode } = useGlobSetting();
   const { configs, isOriginal, isCommon, fetchConfigs } = useInitConfigs();
-  const { enhancedConfigs, hiddenList, data, updateData, updateEnhancedConfigs } = useInitPage(title);
+  const { enhancedConfigs, hiddenList, data, updateData, updateEnhancedConfigs, mainTitle } = useInitPage(title);
   const route = useRoute();
   // const router = useRouter();
-  const isDataRealTime = ref(sysDataType === 'monitor');
+  // const isDataRealTime = ref(sysDataType === 'monitor');
   // const showBar = ref(true);
   const loading = ref(false);
   const showModules = ref(true);
@@ -123,8 +123,9 @@
   // }
 
   function refresh() {
-    fetchConfigs(isDataRealTime.value ? 'vent_realtime' : 'vent').then(() => {
-      configs.value = testConfigSDG;
+    // fetchConfigs(isDataRealTime.value ? 'vent_realtime' : 'vent').then(() => {
+    fetchConfigs('vent').then(() => {
+      // configs.value = testConfigSDG;
       updateEnhancedConfigs(configs.value);
 
       // 测风装置	windrect

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

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

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

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

+ 250 - 0
src/views/vent/monitorManager/balancePressMonitor/indexSP.vue

@@ -0,0 +1,250 @@
+<template>
+  <customHeader
+    :fieldNames="{ label: 'systemname', value: 'id', options: 'children' }"
+    :options="options"
+    @change="getSelectRow"
+    :optionValue="optionValue"
+    >均压与低氧管控</customHeader
+  >
+  <div class="bg" style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden; z-index: 0">
+    <a-spin :spinning="loading" />
+    <div id="balancePress3D" v-show="!loading" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
+    <!-- <div id="damper3DCSS" v-show="!loading" style="width: 100%; height: 100%; top:0; left: 0; position: absolute; overflow: hidden;">
+      <div>
+        <div ref="elementContent" class="elementContent">
+          <p><span class="data-title">压力(Pa):</span>{{selectData.frontRearDP}}</p>
+          <p><span class="data-title">动力源压力(MPa):</span>{{selectData.sourcePressure}}</p>
+          <p><span class="data-title">故障诊断:</span>
+            <i
+              :class="{'state-icon': true, 'open': selectData.messageBoxStatus, 'close': !selectData.messageBoxStatus}"
+            ></i>{{selectData.fault}}</p>
+        </div>
+      </div>
+    </div> -->
+  </div>
+  <div class="scene-box">
+    <div class="center-container">
+      <balancePressHome v-if="activeKey == 'monitor'" :deviceId="optionValue" />
+      <div v-else class="history-group">
+        <div class="device-button-group" v-if="deviceList.length > 0">
+          <div
+            class="device-button"
+            :class="{ 'device-active': deviceActive == device.deviceType }"
+            v-for="(device, index) in deviceList"
+            :key="index"
+            @click="deviceChange(index)"
+            >{{ device.deviceName }}</div
+          >
+        </div>
+        <div class="history-container">
+          <balancePressHistory
+            v-if="activeKey == 'monitor_history'"
+            ref="historyTable"
+            class="vent-margin-t-20"
+            :deviceId="optionValue"
+            :device-type="deviceType"
+          />
+          <balancePressHandleHistoryVue
+            v-if="activeKey == 'handler_history'"
+            ref="alarmHistoryTable"
+            class="vent-margin-t-20"
+            :deviceId="optionValue"
+            :device-type="deviceType"
+          />
+          <balancePressAlarmHistory
+            v-if="activeKey == 'faultRecord'"
+            ref="handlerHistoryTable"
+            class="vent-margin-t-20"
+            :deviceId="optionValue"
+            :device-type="deviceType"
+          />
+        </div>
+      </div>
+    </div>
+    <BottomMenu @change="changeActive" />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import customHeader from '/@/components/vent/customHeader.vue';
+  import { onBeforeMount, ref, onMounted, onUnmounted } from 'vue';
+  import { list, getTableList } from './balancePress.api';
+  import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
+  import balancePressHome from './components/balancePressHomeSP.vue';
+  import balancePressHistory from './components/balancePressHistory.vue';
+  import balancePressHandleHistoryVue from './components/balancePressHandleHistory.vue';
+  import balancePressAlarmHistory from './components/balancePressAlarmHistory.vue';
+  import { useRouter } from 'vue-router';
+
+  type DeviceType = { deviceType: string; deviceName: string; datalist: any[] };
+
+  const { currentRoute } = useRouter();
+  const activeKey = ref('monitor');
+  const loading = ref(false);
+
+  const historyTable = ref();
+  const alarmHistoryTable = ref();
+  const handlerHistoryTable = ref();
+
+  //关联设备
+  const deviceList = ref<DeviceType[]>([]);
+  const deviceActive = ref('');
+  const deviceType = ref('');
+
+  const options = ref();
+  const optionValue = ref('');
+
+  function changeActive(activeValue) {
+    activeKey.value = activeValue;
+  }
+
+  function deviceChange(index) {
+    deviceActive.value = deviceType.value = deviceList.value[index].deviceType;
+  }
+
+  // 查询关联设备列表
+  async function getDeviceList() {
+    const res = await list({ devicetype: 'sys', systemID: optionValue.value });
+
+    const result = res.msgTxt;
+    const deviceArr: DeviceType[] = [];
+    result.forEach((item) => {
+      const data = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      });
+      if (item.type != 'sys') {
+        deviceArr.unshift({
+          deviceType: item.type,
+          deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'],
+          datalist: data,
+        });
+      }
+    });
+    deviceList.value = deviceArr;
+    deviceActive.value = deviceArr[0].deviceType;
+    deviceChange(0);
+  }
+
+  async function getSysDataSource() {
+    const res = await getTableList({ strtype: 'sys_surface_junya', pagetype: 'normal' });
+    if (!options.value) {
+      // 初始时选择第一条数据
+      options.value = res.records || [];
+      if (!optionValue.value) {
+        optionValue.value = options.value[0]['id'];
+        getDeviceList();
+      }
+    }
+  }
+
+  // 切换检测数据
+  function getSelectRow(deviceID) {
+    // const currentData = options.value.find((item: any) => {
+    //   return item.id == deviceID
+    // })
+    optionValue.value = deviceID;
+    getDeviceList();
+  }
+
+  onBeforeMount(() => {});
+
+  onMounted(async () => {
+    if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
+      optionValue.value = currentRoute.value['query']['id'] as string;
+    }
+    await getSysDataSource();
+  });
+
+  onUnmounted(() => {});
+</script>
+<style lang="less" scoped>
+  @import '/@/design/vent/modal.less';
+  @ventSpace: zxm;
+  .scene-box {
+    margin-top: 20px;
+    pointer-events: none;
+    .history-group {
+      padding: 0 20px;
+      .history-container {
+        position: relative;
+        background: #6195af1a;
+        width: calc(100% + 10px);
+        top: 0px;
+        left: -10px;
+        border: 1px solid #00fffd22;
+        padding: 10px 0;
+        box-shadow: 0 0 20px #44b4ff33 inset;
+      }
+    }
+    .device-button-group {
+      // margin: 0 20px;
+      display: flex;
+      pointer-events: auto;
+      position: relative;
+      margin-top: 90px;
+      &::after {
+        position: absolute;
+        content: '';
+        width: calc(100% + 10px);
+        height: 2px;
+        top: 30px;
+        left: -10px;
+        border-bottom: 1px solid #0efcff;
+      }
+      .device-button {
+        padding: 4px 15px;
+        position: relative;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        font-size: 14px;
+
+        color: #fff;
+        cursor: pointer;
+        margin: 0 3px;
+
+        &::before {
+          content: '';
+          position: absolute;
+          top: 0;
+          right: 0;
+          bottom: 0;
+          left: 0;
+          border: 1px solid #6176af;
+          transform: skewX(-38deg);
+          background-color: rgba(0, 77, 103, 85%);
+          z-index: -1;
+        }
+      }
+      .device-active {
+        // color: #0efcff;
+        &::before {
+          border-color: #0efcff;
+          box-shadow: 1px 1px 3px 1px #0efcff inset;
+        }
+      }
+    }
+  }
+  .center-container {
+    width: 100%;
+    height: calc(100% - 200px);
+  }
+
+  .input-box {
+    display: flex;
+    align-items: center;
+    padding-left: 10px;
+
+    .input-title {
+      color: #73e8fe;
+      width: auto;
+    }
+
+    .@{ventSpace}-input-number {
+      border-color: #ffffff88 !important;
+    }
+
+    margin-right: 10px;
+  }
+</style>

+ 15 - 116
src/views/vent/monitorManager/comment/GroupMonitorTable.vue

@@ -101,105 +101,6 @@
     }
   };
 
-  /** 定义table Columns */
-  // function setColumns(columnsType) {
-  //   const isCheckColumn = {
-  //     title: '',
-  //     dataIndex: 'isCheck',
-  //     width: 40,
-  //     align: 'center',
-  //     customCell: (_, index) => {
-
-  //       if (index % 3 == 0) {
-  //         return { rowSpan: 3 };
-  //       } else {
-  //         return { rowSpan: 0 };
-  //       }
-  //     },
-  //   };
-  //   const indexColumn = {
-  //     title: '序号',
-  //     dataIndex: 'key',
-  //     width: 80,
-  //     align: 'center',
-  //     customCell: (_, index) => {
-  //       if (index % 3 == 0) {
-  //         return { rowSpan: 3 };
-  //       } else {
-  //         return { rowSpan: 0 };
-  //       }
-  //     },
-  //     customRender: function ({ index }) {
-  //       return index / 3 + 1;
-  //     },
-  //   };
-  //   const runDevice = {
-  //     title: '风机',
-  //     dataIndex: 'runDevice',
-  //     width: 80,
-  //     align: 'center',
-  //   };
-
-  //   columns.value = getTableHeaderColumns(columnsType);
-  //   console.log('风机columns------------------>', columnsType);
-  //   if (columns.value && columns.value.length < 1) {
-  //     columns.value = getTableHeaderColumns(columnsType.split('_')[0] + '_monitor');
-  //   }
-
-  //   const strinstallpos = columns.value.find((item) => {
-  //     return item.dataIndex === 'strinstallpos' || item.dataIndex === 'strname';
-  //   });
-  //   if (strinstallpos) {
-  //     strinstallpos.customCell = (_, index) => {
-  //       if (index % 3 == 0) {
-  //         return { rowSpan: 3 };
-  //       } else {
-  //         return { rowSpan: 0 };
-  //       }
-  //     };
-  //   }
-  //   columns.value.forEach((item) => {
-  //     if (item.dataIndex === 'strinstallpos' || item.dataIndex === 'strname' || item.dataIndex.endsWith('_merge')) {
-  //       item.customCell = (_, index) => {
-  //         if (index % 3 == 0) {
-  //           return { rowSpan: 3 };
-  //         } else {
-  //           return { rowSpan: 0 };
-  //         }
-  //       };
-  //     }
-  //   });
-
-  //   columns.value.splice(1, 0, runDevice);
-  //   if (props.isShowSelect) {
-  //     columns.value = [isCheckColumn, indexColumn, ...columns.value];
-  //   } else {
-  //     columns.value = [indexColumn, ...columns.value];
-  //   }
-
-  //   if (props.isAction) {
-  //     columns.value = [
-  //       ...columns.value,
-  //       {
-  //         title: '操作',
-  //         dataIndex: 'operation',
-  //         width: 120,
-  //         align: 'center',
-  //         slots: { customRender: 'operation' },
-  //         customCell: (_, index) => {
-  //           if (index % 3 == 0) {
-  //             return { rowSpan: 3 };
-  //           } else {
-  //             return { rowSpan: 0 };
-  //           }
-  //         },
-  //       },
-  //     ];
-  //   }
-  //   // columns.value = [...columns.value, ...columns.value]
-  //   return columns;
-  // }
-
   function setColumns(columnsType) {
     const isCheckColumn = {
       title: '',
@@ -250,7 +151,6 @@
     });
     if (strinstallpos) {
       strinstallpos.customCell = (_, index) => {
-        debugger;
         const columnNum = _.modalTyoe ? (_.modalTyoe.endsWith('_3') ? 3 : _.modalTyoe.endsWith('_1') ? 1 : 2) : 2;
         if (_.rowIndex % columnNum == 0) {
           return { rowSpan: columnNum };
@@ -330,7 +230,10 @@
       const list: unknown[] = [];
       newVal.forEach((item, index) => {
         const data: any = toRaw(item);
-        const modalTyoe = data.modalTyoe; ///
+        if (data.deviceType.startsWith('fanlocal') && data.install_kind) {
+          data['modalTyoe'] = data.install_kind;
+        }
+        const modalTyoe = data.modalTyoe;
         const resultData1 = {};
         const resultData2 = {};
         const resultData3 = {};
@@ -391,34 +294,30 @@
           }
         });
         resultData1['deviceID'] = resultData2['deviceID'] = data['deviceID'];
-        debugger;
         if (props.columnsType.startsWith('fanlocal') && sysOrgCode !== 'zmhjhzmy') {
           resultData1['runDevice'] = '主机';
           resultData2['runDevice'] = '备机';
-          resultData1['rowIndex'] = 0;
-          resultData2['rowIndex'] = 1;
-          resultData1['index'] = index;
-          resultData2['index'] = index;
         } else {
           resultData1['runDevice'] = '1#风机';
           resultData2['runDevice'] = '2#风机';
           resultData3['runDevice'] = '3#风机';
-          resultData1['modalTyoe'] = modalTyoe;
-          resultData2['modalTyoe'] = modalTyoe;
-          resultData3['modalTyoe'] = modalTyoe;
+        }
+        resultData1['modalTyoe'] = modalTyoe;
+        resultData2['modalTyoe'] = modalTyoe;
+        resultData3['modalTyoe'] = modalTyoe;
 
-          resultData1['rowIndex'] = 0;
-          resultData2['rowIndex'] = 1;
-          resultData3['rowIndex'] = 2;
+        resultData1['rowIndex'] = 0;
+        resultData2['rowIndex'] = 1;
+        resultData3['rowIndex'] = 2;
 
-          resultData1['index'] = index;
-          resultData2['index'] = index;
-          resultData3['index'] = index;
-        }
+        resultData1['index'] = index;
+        resultData2['index'] = index;
+        resultData3['index'] = index;
         if (modalTyoe && modalTyoe.endsWith('_3')) {
           list.push(resultData1, resultData2, resultData3);
         } else if (modalTyoe && modalTyoe.endsWith('_1')) {
           list.push(resultData1);
+          // list.push(resultData1, resultData2);
         } else {
           list.push(resultData1, resultData2);
         }

+ 6 - 1
src/views/vent/monitorManager/deviceMonitor/staticSheets/commonSheet.vue

@@ -295,7 +295,12 @@
 </script>
 <style lang="less" scoped>
   @import url('/@/design/theme.less');
-
+  @{theme-green} {
+    .sheet-bg {
+      --sheet-bg: url(/@/assets/images/themify/green/vent/sheet-bg.png);
+      --sheet-header: url(/@/assets/images/themify/green/vent/sheet-header.png);
+    }
+  }
   @{theme-deepblue} {
     .sheet-bg {
       --sheet-bg: url(/@/assets/images/themify/deepblue/vent/sheet-bg.png);

+ 6 - 1
src/views/vent/monitorManager/deviceMonitor/staticSheets/dustSheet.vue

@@ -103,7 +103,12 @@
 </script>
 <style lang="less" scoped>
   @import url('/@/design/theme.less');
-
+  @{theme-green} {
+    .sheet-bg {
+      --sheet-bg: url(/@/assets/images/themify/green/vent/sheet-bg.png);
+      --sheet-header: url(/@/assets/images/themify/green/vent/sheet-header.png);
+    }
+  }
   @{theme-deepblue} {
     .sheet-bg {
       --sheet-bg: url(/@/assets/images/themify/deepblue/vent/sheet-bg.png);

+ 6 - 1
src/views/vent/monitorManager/deviceMonitor/staticSheets/fireSheet.vue

@@ -146,7 +146,12 @@
 </script>
 <style lang="less" scoped>
   @import url('/@/design/theme.less');
-
+  @{theme-green} {
+    .sheet-bg {
+      --sheet-bg: url(/@/assets/images/themify/green/vent/sheet-bg.png);
+      --sheet-header: url(/@/assets/images/themify/green/vent/sheet-header.png);
+    }
+  }
   @{theme-deepblue} {
     .sheet-bg {
       --sheet-bg: url(/@/assets/images/themify/deepblue/vent/sheet-bg.png);

+ 6 - 1
src/views/vent/monitorManager/deviceMonitor/staticSheets/gasSheet.vue

@@ -151,7 +151,12 @@
 </script>
 <style lang="less" scoped>
   @import url('/@/design/theme.less');
-
+  @{theme-green} {
+    .sheet-bg {
+      --sheet-bg: url(/@/assets/images/themify/green/vent/sheet-bg.png);
+      --sheet-header: url(/@/assets/images/themify/green/vent/sheet-header.png);
+    }
+  }
   @{theme-deepblue} {
     .sheet-bg {
       --sheet-bg: url(/@/assets/images/themify/deepblue/vent/sheet-bg.png);

+ 6 - 1
src/views/vent/monitorManager/deviceMonitor/staticSheets/ventilateSheet.vue

@@ -263,7 +263,12 @@
 </script>
 <style lang="less" scoped>
   @import url('/@/design/theme.less');
-
+  @{theme-green} {
+    .sheet-bg {
+      --sheet-bg: url(/@/assets/images/themify/green/vent/sheet-bg.png);
+      --sheet-header: url(/@/assets/images/themify/green/vent/sheet-header.png);
+    }
+  }
   @{theme-deepblue} {
     .sheet-bg {
       --sheet-bg: url(/@/assets/images/themify/deepblue/vent/sheet-bg.png);

+ 400 - 0
src/views/vent/monitorManager/fanLocalMonitor/fanLocal.threejs.single.ts

@@ -0,0 +1,400 @@
+import * as THREE from 'three';
+import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer';
+import { getTextCanvas, setModalCenter } from '/@/utils/threejs/util';
+import Smoke from '/@/views/vent/comment/threejs/Smoke';
+import gsap from 'gsap';
+
+// 本模型的上下文对象,用于实现本模型的特定功能,代码参考了旧有的 fanLocal.three.ts
+class ModelContext {
+  model;
+  modelName = 'jbfj-single';
+  group: THREE.Object3D | null = null;
+  fanType?: string;
+  topSmoke?: Smoke;
+  downSmoke?: Smoke;
+  returnSmoke?: Smoke;
+  topLife?: number;
+  downLife?: number;
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    // optional implementation
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel([this.modelName]).then(async (gltf) => {
+        this.group = gltf[0];
+        if (this.group) {
+          setModalCenter(this.group);
+          this.addLight();
+          this.initFly();
+          this.setModalPosition();
+          resolve(null);
+        }
+      });
+    });
+  }
+
+  destroy() {
+    if (this.model) {
+      this.model.isRender = false;
+      this.clearFly();
+      this.topSmoke = undefined;
+      this.downSmoke = undefined;
+      this.returnSmoke = undefined;
+      // @ts-ignore
+      this.group = undefined;
+      this.model.destroy();
+    }
+  }
+
+  async initFly() {
+    const topCurve = [
+      {
+        path0: new THREE.Vector3(7.698, 0.398, 0.19),
+        path1: new THREE.Vector3(-0.65, 0.398, 0.19),
+        isSpread: true,
+        spreadDirection: 0, //
+      },
+      {
+        path0: new THREE.Vector3(-0.65, 0.398, 0.19),
+        path1: new THREE.Vector3(-7.599, 0.398, 0.19),
+        isSpread: true,
+        spreadRang: 1,
+        spreadDirection: 1, //
+      },
+    ];
+
+    if (!this.topSmoke) {
+      this.topSmoke = new Smoke('/model/img/texture-smoke.png', '#ffffff', 2, 0.35, 3.7, 100);
+      this.topSmoke.setPath(topCurve);
+      await this.topSmoke.setPoints();
+      this.group?.add(this.topSmoke.points);
+    }
+  }
+
+  playSmoke(selectData) {
+    // debugger;
+    if (selectData['Fan1StartStatus'] == '1') {
+      // 主风机打开
+      this.setSmokeFrequency('top', 40);
+      this.runFly('top', 'open');
+    } else {
+      // 备风机关闭
+      this.runFly('top', 'close');
+    }
+
+    if (selectData['Fan1StartStatus'] != '1') {
+      this.runFly('all', 'close');
+    }
+  }
+
+  runFly(deviceType, state) {
+    if (state === 'open') {
+      if (deviceType === 'top') {
+        if (this.downSmoke && this.downSmoke.frameId) {
+          this.downSmoke.stopSmoke();
+        }
+        if (this.topSmoke && !this.topSmoke.frameId) {
+          this.topSmoke.startSmoke();
+        }
+      }
+    } else {
+      if (deviceType === 'top') {
+        if (this.topSmoke && this.topSmoke.frameId) {
+          this.topSmoke.stopSmoke();
+        }
+      }
+    }
+    if (deviceType === 'all' && state === 'close') {
+      this.returnSmoke?.stopSmoke();
+    }
+  }
+
+  setSmokeFrequency(deviceType, frequency) {
+    const life = (frequency - 30) * 25;
+    let duration = 0;
+    let smoke;
+
+    if (deviceType === 'top') {
+      if (this.topLife == life) {
+        return;
+      }
+      this.topLife = life;
+      smoke = this.topSmoke;
+      duration = (Math.abs(life - smoke.life) / 500) * 25;
+    }
+    if (smoke) {
+      gsap.to(smoke, {
+        life: life,
+        duration: duration,
+        ease: 'easeInCubic',
+        overwrite: true,
+      });
+    }
+  }
+
+  addText(selectData) {
+    if (!this.group) {
+      return;
+    }
+    // @ts-ignore
+    const screenDownText = VENT_PARAM['modalText']
+      ? // @ts-ignore
+        VENT_PARAM['modalText']
+      : // @ts-ignore
+      History_Type['type'] == 'remote'
+      ? `国能神东煤炭集团监制`
+      : '煤炭科学技术研究院有限公司研制';
+
+    const screenDownTextX = 80 - (screenDownText.length - 10) * 6;
+    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.airSupplyDistence_merge
+            ? selectData.airSupplyDistence_merge
+            : 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: screenDownText,
+        font: 'normal 28px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: screenDownTextX,
+        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 = this.group?.getObjectByName('monitorText');
+      if (monitorPlane) {
+        // @ts-ignore-next-line
+        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);
+        this.group?.add(planeMesh);
+      }
+    });
+  }
+
+  addCssText() {
+    if (!this.group) return;
+
+    if (!this.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);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.group.getObjectByName('text2')) {
+      const element = document.getElementById('outBox') as HTMLElement;
+      if (element) {
+        const fanLocalCSS3D = new CSS3DObject(element);
+        fanLocalCSS3D.name = 'text2';
+        fanLocalCSS3D.scale.set(0.15, 0.15, 0.15);
+        fanLocalCSS3D.rotation.y = -Math.PI / 2;
+        fanLocalCSS3D.position.set(85.62, 17.65, 7.71);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.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);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.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);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.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);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.group.getObjectByName('text7')) {
+      const element = document.getElementById('inputBox0') as HTMLElement;
+      if (element) {
+        const fanLocalCSS3D = new CSS3DObject(element);
+        fanLocalCSS3D.name = 'text7';
+        fanLocalCSS3D.scale.set(0.04, 0.04, 0.04);
+        fanLocalCSS3D.rotation.y = -Math.PI / 2;
+        fanLocalCSS3D.position.set(-84.23, 4.97, -18.92);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.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.47, 6.56, -19.47);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.group.getObjectByName('text8')) {
+      const element = document.getElementById('gasBox3') as HTMLElement;
+      if (element) {
+        const fanLocalCSS3D = new CSS3DObject(element);
+        fanLocalCSS3D.name = 'text8';
+        fanLocalCSS3D.scale.set(0.03, 0.03, 0.03);
+        fanLocalCSS3D.rotation.y = -Math.PI / 2;
+        fanLocalCSS3D.position.set(-90.04, 6, 5);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.group.getObjectByName('text9')) {
+      const element = document.getElementById('gasBox2') as HTMLElement;
+      if (element) {
+        const fanLocalCSS3D = new CSS3DObject(element);
+        fanLocalCSS3D.name = 'text9';
+        fanLocalCSS3D.scale.set(0.07, 0.07, 0.07);
+        fanLocalCSS3D.rotation.y = -Math.PI / 2;
+        fanLocalCSS3D.position.set(-8, 7.46, -35.28);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+    if (!this.group.getObjectByName('text10')) {
+      const element = document.getElementById('gasBox1') as HTMLElement;
+      if (element) {
+        const fanLocalCSS3D = new CSS3DObject(element);
+        fanLocalCSS3D.name = 'text10';
+        fanLocalCSS3D.scale.set(0.1, 0.1, 0.1);
+        fanLocalCSS3D.rotation.y = -Math.PI / 2;
+        fanLocalCSS3D.position.set(80, 9, -43);
+        this.group.add(fanLocalCSS3D);
+      }
+    }
+  }
+
+  clearFly() {
+    if (this.topSmoke) this.topSmoke.clearSmoke();
+    if (this.downSmoke) this.downSmoke.clearSmoke();
+    if (this.returnSmoke) this.returnSmoke.clearSmoke();
+  }
+
+  // 设置模型位置
+  setModalPosition() {
+    if (!this.group) return;
+    this.group.scale.set(13, 13, 13);
+    this.group.position.set(0, -10, -50);
+  }
+}
+export default ModelContext;

+ 56 - 37
src/views/vent/monitorManager/fanLocalMonitor/fanLocal.threejs.ts

@@ -1,10 +1,9 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
-import FanLocal from './fanLocal.threejs.base';
-import FanLocalTwo from './fanLocal.threejs.Two';
-import FanLocalDual from './fanLocalDual.threejs.base';
+
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
+import { getDictItemsByCode } from '/@/utils/dict';
 
 /** 模型总控制器 */
 let model: UseThree;
@@ -66,7 +65,7 @@ function initEventListender() {
 // }
 
 /** 设置模型类型并切换,不同的类型通常对应不同的具体模型,在模型总控制器下的具体模型会根据传入的参数彼此交互、切换 */
-export function setModelType(modelType: 'fanLocal' | 'fanLocalDual' | string, subModelType: string, data?: any) {
+export function setModelType(modelType: 'fanLocal' | 'fanLocalDual' | 'fanLocalSingle' | string, subModelType: string, data?: any) {
   return new Promise((resolve, reject) => {
     if (!model) return reject('模型控制器未初始化');
     // 判断是否是同一个/类模型
@@ -86,7 +85,7 @@ export function setModelType(modelType: 'fanLocal' | 'fanLocalDual' | string, su
 
       if (modelType === type) {
         group = context?.group as THREE.Object3D;
-        context.setModelType(subModelType, data);
+        if (context.setModelType) context.setModelType(subModelType, data);
 
         // 还没添加到控制器的添加进去
         if (!model.scene?.getObjectByName(group.name) && group) {
@@ -107,10 +106,8 @@ export function setModelType(modelType: 'fanLocal' | 'fanLocalDual' | string, su
           animateCamera(oldCameraPosition, { x: 0, y: 0, z: 0 }, { x: -1.85, y: 13.58, z: 37.39 }, { x: -1.83, y: 2.58, z: -0.75 }, model, 0.8);
         }
         if (type == 'fanLocalDual') {
-          // if (!isUpdate) {
           const oldCameraPosition = { x: -693, y: 474, z: 398 };
           animateCamera(oldCameraPosition, { x: 0, y: 0, z: 0 }, { x: 14.83, y: 16.9, z: 36.46 }, { x: 0, y: 0, z: 0 }, model, 0.8);
-          // }
         }
 
         resolve(null);
@@ -131,29 +128,55 @@ export function mountedThree(sceneSelctor: string, cssSelectors: string[]) {
       model.renderer.sortObjects = true;
     }
 
-    const model1 = new FanLocal(model);
-    await model1.mountedThree();
-    modelContextList.push({
-      type: 'fanLocal',
-      context: model1,
-    });
-
-    const model2 = new FanLocalDual(model);
-    await model2.mountedThree();
-    // 暂时先不加双行
-    modelContextList.push({
-      type: 'fanLocalDual',
-      context: model2,
-    });
-
-    const model3 = new FanLocalTwo(model);
-    const flag = await model3.mountedThree();
-
-    if (flag)
-      modelContextList.push({
-        type: 'fanLocalTwo',
-        context: model3,
-      });
+    // 这里根据字典判断
+    const dictCodes = getDictItemsByCode('fanlocal_install_kind');
+    if (dictCodes && dictCodes.length > 0) {
+      for (let i = 0; i < dictCodes.length; i++) {
+        const dict = dictCodes[i];
+        switch (dict.value) {
+          case 'single':
+            const FanLocal = await import('./fanLocal.threejs.base');
+            const model1 = new FanLocal.default(model);
+            await model1.mountedThree();
+            modelContextList.push({
+              type: 'fanLocal',
+              context: model1,
+            });
+            break;
+          case 'dual_inner':
+          case 'dual_outer':
+            if (modelContextList.find((item) => item.type == 'fanLocalDual')) continue;
+            const FanLocalDual = await import('./fanLocalDual.threejs.base');
+            const model2 = new FanLocalDual.default(model);
+            await model2.mountedThree();
+            // 暂时先不加双行
+            modelContextList.push({
+              type: 'fanLocalDual',
+              context: model2,
+            });
+            break;
+          case 'fanLocalTwo':
+            const FanLocalTwo = await import('./fanLocal.threejs.Two');
+            const model3 = new FanLocalTwo.default(model);
+            const flag = await model3.mountedThree();
+            if (flag)
+              modelContextList.push({
+                type: 'fanLocalTwo',
+                context: model3,
+              });
+            break;
+          case 'fanlocal_1':
+            const FanLocalSingle = await import('./fanLocal.threejs.single');
+            const model4 = new FanLocalSingle.default(model);
+            await model4.mountedThree();
+            modelContextList.push({
+              type: 'fanLocalSingle',
+              context: model4,
+            });
+            break;
+        }
+      }
+    }
 
     initEventListender();
     setCamera();
@@ -182,12 +205,8 @@ export function addCssText() {
   if (modelContextList[2] && modelContextList[2].context && modelContextList[2].context['addCssText']) modelContextList[2].context['addCssText']();
 }
 export function playSmoke(d) {
-  if (modelContextList[0]) {
-    // @ts-ignore
-    modelContextList[0].context?.playSmoke(d);
-  }
-  if (modelContextList[2]) {
-    // @ts-ignore
-    modelContextList[2].context?.playSmoke(d);
+  for (let i = 0; i < modelContextList.length; i++) {
+    const item = modelContextList[i];
+    if (item.context && item.context.playSmoke) item.context.playSmoke(d);
   }
 }

+ 16 - 7
src/views/vent/monitorManager/fanLocalMonitor/index.vue

@@ -271,7 +271,7 @@
               fanTitles[0]
             }}</div>
             <div
-              v-if="selectData && ((selectData['modalTyoe'] && !selectData['modalTyoe'].endsWith('_1')) || !selectData['modalTyoe'])"
+              v-if="selectData && ((selectData['install_kind'] && !selectData['install_kind'].endsWith('_1')) || !selectData['install_kind'])"
               class="tab-item"
               :class="{ 'tab-item-active-r': warningMonitorRowIndex === 1 }"
               @click="selectDevice('warningMonitorRowIndex', 1)"
@@ -342,7 +342,7 @@
                 fanTitles[0]
               }}</div>
               <div
-                v-if="selectData && ((selectData['modalTyoe'] && !selectData['modalTyoe'].endsWith('_1')) || !selectData['modalTyoe'])"
+                v-if="selectData && ((selectData['install_kind'] && !selectData['install_kind'].endsWith('_1')) || !selectData['install_kind'])"
                 class="tab-item"
                 :class="{ 'tab-item-active-r': dataMonitorRowIndex == 1 }"
                 @click="selectDevice('dataMonitorRowIndex', 1)"
@@ -609,7 +609,10 @@
             <a-radio value="stop">停止</a-radio>
           </a-radio-group>
         </div>
-        <div class="startSmoke-select">
+        <div
+          v-if="selectData && ((selectData['install_kind'] && !selectData['install_kind'].endsWith('_1')) || !selectData['install_kind'])"
+          class="startSmoke-select"
+        >
           <div class="label">备机:</div>
           <a-radio-group v-model:value="mainWindIsShow2" @change="changeMotor" name="localWind2">
             <a-radio value="open">开启</a-radio>
@@ -625,7 +628,10 @@
           <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
+          v-if="selectData && ((selectData['install_kind'] && !selectData['install_kind'].endsWith('_1')) || !selectData['install_kind'])"
+          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>
@@ -638,7 +644,10 @@
           <div class="label">主机:</div>
           <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan1remote')">远程/就地切换</div>
         </div>
-        <div class="startSmoke-select">
+        <div
+          v-if="selectData && ((selectData['install_kind'] && !selectData['install_kind'].endsWith('_1')) || !selectData['install_kind'])"
+          class="startSmoke-select"
+        >
           <div class="label">备机:</div>
           <div :class="{ 'button-box': true, 'button-disable': false }" @click="handleOk('Fan2remote')">远程/就地切换</div>
         </div>
@@ -1332,16 +1341,16 @@
         if (data['install_kind']) {
           const keymap = {
             fanLocalTwo: ['fanLocalTwo', modalType.value],
-            single: ['fanLocal', modalType.value],
+            single: ['fanLocal', modalType.value], //单巷(默认两风筒)
             dual_inner: ['fanLocalDual', 'inner'],
             dual_outer: ['fanLocalDual', 'outer'],
+            fanlocal_1: ['fanLocalSingle', modalType.value], //单巷单风筒
           };
           mainModelType.value = keymap[data['install_kind']][0];
           modalType.value = keymap[data['install_kind']][1];
         } else {
           // 为了兼容没有添加 install_kind 的旧的单巷
           mainModelType.value = 'fanLocal';
-          // mainModelType.value = 'fanLocalTwo';
         }
       }
       setModelType(mainModelType.value, modalType.value, fanDualArray.value);

+ 174 - 0
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.fire.redGate.ts

@@ -0,0 +1,174 @@
+import * as THREE from 'three';
+import { useAppStore } from '/@/store/modules/app';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class FireDoor {
+  modelName = 'fireDoor-redGate';
+  model; //
+  group;
+  isLRAnimation = true; // 是否开启左右摇摆动画
+  direction = 1; // 摇摆方向
+  animationTimer: NodeJS.Timeout | null = null; // 摇摆开启定时器
+  player1;
+  player2;
+  deviceDetailCSS3D;
+  playerStartClickTime1 = new Date().getTime();
+  playerStartClickTime2 = new Date().getTime();
+
+  fmClock = new THREE.Clock();
+  mixers: THREE.AnimationMixer | undefined;
+  appStore = useAppStore();
+  damperOpenMesh;
+  damperClosedMesh;
+
+  clipActionArr = {
+    door: null as unknown as THREE.AnimationAction,
+  };
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
+    directionalLight.position.set(344, 690, 344);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    const pointLight2 = new THREE.PointLight(0xffeeee, 1, 300);
+    pointLight2.position.set(-4, 10, 1.8);
+    pointLight2.shadow.bias = 0.05;
+    this.group?.add(pointLight2);
+
+    const pointLight3 = new THREE.PointLight(0xffeeee, 1, 200);
+    pointLight3.position.set(-0.5, -0.5, 0.75);
+    pointLight3.shadow.bias = 0.05;
+    this.group?.add(pointLight3);
+  }
+  resetCamera() {
+    this.model.camera.far = 274;
+    this.model.orbitControls?.update();
+    this.model.camera.updateProjectionMatrix();
+  }
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-20, 20, 9);
+  }
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(1);
+    }
+  }
+
+  /* 点击风门 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    console.log('摄像头控制信息', this.model?.orbitControls, this.model?.camera);
+  }
+
+  mouseUpModel() {}
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    const fireGroup = this.group.children[0]?.getObjectByName('fireDoor-redGate');
+    if (fireGroup) {
+      // const doorGroup = new THREE.Object3D();
+      // doorGroup.add(fireGroup.children[0].getObjectByName('men_1'));
+      // doorGroup.add(fireGroup.children[0].getObjectByName('men2'));
+      const tracks = fireGroup.animations[0].tracks;
+
+      this.mixers = new THREE.AnimationMixer(fireGroup);
+
+      const door = new THREE.AnimationClip('door', 2, tracks);
+      const frontClipAction = this.mixers.clipAction(door, fireGroup.children[0]);
+      frontClipAction.clampWhenFinished = true;
+      frontClipAction.loop = THREE.LoopOnce;
+      this.clipActionArr.door = frontClipAction;
+    }
+  }
+
+  // 播放动画
+  play(handlerState, timeScale = 0.1) {
+    let handler = () => {};
+    if (this.clipActionArr.door) {
+      switch (handlerState) {
+        case 1: // 打开门
+          handler = () => {
+            this.clipActionArr.door.paused = true;
+            this.clipActionArr.door.reset();
+            this.clipActionArr.door.time = 0.1;
+            this.clipActionArr.door.timeScale = timeScale;
+            this.clipActionArr.door.play();
+            this.fmClock.start();
+          };
+          break;
+        case 2: // 关闭门
+          handler = () => {
+            this.clipActionArr.door.paused = true;
+            this.clipActionArr.door.reset(); //
+            this.clipActionArr.door.time = 1.1;
+            this.clipActionArr.door.timeScale = -timeScale;
+            this.clipActionArr.door.play();
+            this.fmClock.start();
+          };
+          break;
+        default:
+      }
+      handler();
+    }
+  }
+
+  resetAnimate() {
+    this.clipActionArr.door.reset();
+    this.clipActionArr.door.time = 0.1;
+    this.clipActionArr.door.stop();
+    this.fmClock.stop();
+  }
+
+  mountedThree() {
+    this.group = new THREE.Object3D();
+    this.group.name = this.modelName;
+
+    return new Promise((resolve) => {
+      if (!this.model) {
+        resolve(null);
+      }
+      this.model.setGLTFModel([this.modelName], this.group).then(() => {
+        this.setModalPosition();
+        console.log(this.group);
+        // 初始化左右摇摆动画;
+        this.initAnimation();
+        // this.addLight();
+        // this.model.animate();
+        // resolve(this.model);
+      });
+    });
+  }
+
+  destroy() {
+    if (this.model) {
+      if (this.mixers) {
+        this.mixers.uncacheClip(this.clipActionArr.door.getClip());
+        this.mixers.uncacheAction(this.clipActionArr.door.getClip(), this.group);
+        this.mixers.uncacheRoot(this.group);
+
+        if (this.model.animations[0]) this.model.animations[0].tracks = [];
+      }
+      this.model.clearGroup(this.group);
+      this.clipActionArr.door = undefined;
+
+      this.mixers = undefined;
+
+      // document.getElementById('damper3D').parentElement.remove(document.getElementById('damper3D'))
+    }
+  }
+}
+export default FireDoor;

+ 7 - 0
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.fire.ts

@@ -130,6 +130,13 @@ class FireDoor {
     }
   }
 
+  resetAnimate() {
+    this.clipActionArr.door.reset();
+    this.clipActionArr.door.time = 0.1;
+    this.clipActionArr.door.stop();
+    this.fmClock.stop();
+  }
+
   mountedThree() {
     this.group = new THREE.Object3D();
     this.group.name = this.modelName;

+ 7 - 0
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.fireF.ts

@@ -129,6 +129,13 @@ class FireDoorF {
     }
   }
 
+  resetAnimate() {
+    this.clipActionArr.door.reset();
+    this.clipActionArr.door.time = 0.1;
+    this.clipActionArr.door.stop();
+    this.fmClock.stop();
+  }
+
   mountedThree() {
     this.group = new THREE.Object3D();
     this.group.name = this.modelName;

+ 230 - 0
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ssl.ts

@@ -0,0 +1,230 @@
+import * as THREE from 'three';
+import { useAppStore } from '/@/store/modules/app';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class FireDoorSsl {
+  modelName = 'fireDoorSsl';
+  model; //
+  group;
+  isLRAnimation = true; // 是否开启左右摇摆动画
+  direction = 1; // 摇摆方向
+  animationTimer: NodeJS.Timeout | null = null; // 摇摆开启定时器
+  player1;
+  player2;
+  deviceDetailCSS3D;
+  playerStartClickTime1 = new Date().getTime();
+  playerStartClickTime2 = new Date().getTime();
+
+  fmClock = new THREE.Clock();
+  mixers: THREE.AnimationMixer | undefined;
+  appStore = useAppStore();
+  damperOpenMesh;
+  damperClosedMesh;
+
+  clipActionArr: Record<string, THREE.AnimationAction | undefined> = {
+    /** 卷帘门动画 */
+    juanlianmen: undefined,
+    /** 盖板动画 */
+    gaiban: undefined,
+  };
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
+    directionalLight.position.set(344, 690, 344);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    const pointLight2 = new THREE.PointLight(0xffeeee, 1, 300);
+    pointLight2.position.set(-4, 10, 1.8);
+    pointLight2.shadow.bias = 0.05;
+    this.group?.add(pointLight2);
+
+    const pointLight3 = new THREE.PointLight(0xffeeee, 1, 200);
+    pointLight3.position.set(-0.5, -0.5, 0.75);
+    pointLight3.shadow.bias = 0.05;
+    this.group?.add(pointLight3);
+  }
+  resetCamera() {
+    this.model.camera.far = 274;
+    this.model.orbitControls?.update();
+    this.model.camera.updateProjectionMatrix();
+  }
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-20, 20, 9);
+  }
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(2);
+    }
+  }
+
+  /* 点击风门 */
+  mousedownModel(intersects: THREE.Intersection[]) {
+    console.log('摄像头控制信息', intersects);
+  }
+
+  mouseUpModel() {}
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    const group = this.group.children[0];
+    /** 卷帘门的元素名称,pCude34-pCude73 */
+    const eleNames = new Array(40).fill(0).map((_, i) => `pCube${i + 34}`);
+    if (group) {
+      const tracksA: THREE.KeyframeTrack[] = [];
+      const tracksB: THREE.KeyframeTrack[] = [];
+
+      group.animations[0].tracks.forEach((track) => {
+        if (eleNames.some((e) => track.name.includes(e))) {
+          tracksA.push(track);
+        } else {
+          tracksB.push(track);
+        }
+      });
+      this.mixers = new THREE.AnimationMixer(group);
+
+      const juanlianmen = new THREE.AnimationClip('juanlianmen', 10, tracksA);
+      const clipA = this.mixers.clipAction(juanlianmen, group);
+      clipA.clampWhenFinished = true;
+      clipA.loop = THREE.LoopOnce;
+      this.clipActionArr.juanlianmen = clipA;
+
+      const gaiban = new THREE.AnimationClip('gaiban', 10, tracksB);
+      const clipB = this.mixers.clipAction(gaiban, group);
+      clipB.clampWhenFinished = true;
+      clipB.loop = THREE.LoopOnce;
+      this.clipActionArr.gaiban = clipB;
+    }
+  }
+  resetAnimate() {
+    if (this.clipActionArr.juanlianmen) {
+      this.clipActionArr.juanlianmen.reset();
+      this.clipActionArr.juanlianmen.time = 0.1;
+      this.clipActionArr.juanlianmen.stop();
+      this.fmClock.stop();
+    }
+    if (this.clipActionArr.gaiban) {
+      this.clipActionArr.gaiban.reset();
+      this.clipActionArr.gaiban.time = 0.1;
+      this.clipActionArr.gaiban.stop();
+      this.fmClock.stop();
+    }
+  }
+
+  // 播放动画
+  /**
+   * 播放门开关动画的处理函数
+   * @param {number} handlerState - 处理状态,1表示开门,2表示关门
+   * @param {number} [timeScale=0.01] - 动画时间缩放因子,控制动画播放速度
+   */
+  play(handlerState, timeScale = 0.01) {
+    console.log('debug rrr', handlerState);
+    let handler = () => {};
+    switch (handlerState) {
+      case 1: // 打开门
+        handler = () => {
+          if (!this.clipActionArr.juanlianmen) return;
+          this.clipActionArr.juanlianmen.paused = true;
+          this.clipActionArr.juanlianmen.reset();
+          this.clipActionArr.juanlianmen.time = 0.1;
+          this.clipActionArr.juanlianmen.timeScale = timeScale;
+          // this.clipActionArr.juanlianmen.clampWhenFinished = true;
+          this.clipActionArr.juanlianmen.play();
+          if (!this.clipActionArr.gaiban) return;
+          this.clipActionArr.gaiban.paused = true;
+          this.clipActionArr.gaiban.reset();
+          this.clipActionArr.gaiban.time = 0.1;
+          this.clipActionArr.gaiban.timeScale = timeScale;
+          // this.clipActionArr.gaiban.clampWhenFinished = true;
+          this.clipActionArr.gaiban.play();
+          this.fmClock.start();
+
+          // 显示打开前门文字
+          if (this.damperOpenMesh) this.damperOpenMesh.visible = true;
+        };
+        break;
+      case 2: // 关闭门
+        handler = () => {
+          if (!this.clipActionArr.juanlianmen) return;
+          this.clipActionArr.juanlianmen.paused = true;
+          this.clipActionArr.juanlianmen.reset(); //
+          this.clipActionArr.juanlianmen.time = 9;
+          this.clipActionArr.juanlianmen.timeScale = -timeScale;
+          // this.clipActionArr.juanlianmen.clampWhenFinished = true;
+          this.clipActionArr.juanlianmen.play();
+          if (!this.clipActionArr.gaiban) return;
+          this.clipActionArr.gaiban.paused = true;
+          this.clipActionArr.gaiban.reset(); //
+          this.clipActionArr.gaiban.time = 9;
+          this.clipActionArr.gaiban.timeScale = -timeScale;
+          // this.clipActionArr.gaiban.clampWhenFinished = true;
+          this.clipActionArr.gaiban.play();
+          this.fmClock.start();
+
+          if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
+        };
+        break;
+      default:
+    }
+    handler();
+  }
+
+  mountedThree() {
+    this.group = new THREE.Object3D();
+    this.group.name = this.modelName;
+
+    return new Promise((resolve) => {
+      if (!this.model) {
+        resolve(null);
+      }
+      this.model.setGLTFModel(['Fire-door-ssl'], this.group).then(() => {
+        this.setModalPosition();
+        // 初始化左右摇摆动画;
+        this.initAnimation();
+        // this.addLight();
+        // this.model.animate();
+        // resolve(this.model);
+
+        // this.damperOpenMesh = this.group.getObjectByName('Damper_Open_2');
+        // if (this.damperOpenMesh) this.damperOpenMesh.visible = false;
+        // this.damperClosedMesh = this.group.getObjectByName('Damper_Closed_2');
+        // if (this.damperClosedMesh) this.damperClosedMesh.visible = true;
+      });
+    });
+  }
+
+  destroy() {
+    if (!this.model) return;
+    if (this.mixers && this.clipActionArr.juanlianmen && this.clipActionArr.gaiban) {
+      this.mixers.uncacheClip(this.clipActionArr.juanlianmen.getClip());
+      this.mixers.uncacheAction(this.clipActionArr.juanlianmen.getClip(), this.group);
+      this.mixers.uncacheClip(this.clipActionArr.gaiban.getClip());
+      this.mixers.uncacheAction(this.clipActionArr.gaiban.getClip(), this.group);
+      this.mixers.uncacheRoot(this.group);
+
+      if (this.model.animations[0]) this.model.animations[0].tracks = [];
+    }
+    this.model.clearGroup(this.group);
+    this.clipActionArr.juanlianmen = undefined;
+    this.clipActionArr.gaiban = undefined;
+
+    this.mixers = undefined;
+
+    // document.getElementById('damper3D').parentElement.remove(document.getElementById('damper3D'))
+  }
+}
+export default FireDoorSsl;

+ 151 - 74
src/views/vent/monitorManager/fireDoorMonitor/fireDoor.threejs.ts

@@ -1,17 +1,17 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
-import FireDoor from './fireDoor.threejs.fire';
-import FireDoorF from './fireDoor.threejs.fireF';
+import { getDictItemsByCode } from '/@/utils/dict';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
-import { useGlobSetting } from '/@/hooks/setting';
 
 // 模型对象、 文字对象
 let model,
   fireDoor, //液压风门
-  fireDoorF, //液压风门
+  fireDoorF, //保德风门
+  fireDoorSsl, // 思山岭防火门
+  fireDoorRed, // 防火门
   group: THREE.Object3D,
-  fmType = '';
+  fhmType = '';
 
 const { mouseDownFn } = useEvent();
 
@@ -22,12 +22,18 @@ const startAnimation = () => {
   model.canvasContainer?.addEventListener('pointerup', (event) => {
     event.stopPropagation();
     // 单道、 双道
-    if (fmType === 'fireDoor') {
+    if (fhmType === 'fireDoor') {
       fireDoor?.mouseUpModel.call(fireDoor);
     }
-    if (fmType === 'fireDoorF') {
+    if (fhmType === 'fireDoorF') {
       fireDoorF?.mouseUpModel.call(fireDoorF);
     }
+    if (fhmType === 'fireDoorSsl') {
+      fireDoorSsl?.mouseUpModel.call(fireDoorSsl);
+    }
+    if (fhmType === 'fireDoorRed') {
+      fireDoorRed?.mouseUpModel.call(fireDoorRed);
+    }
   });
 };
 
@@ -35,98 +41,135 @@ const startAnimation = () => {
 const mouseEvent = (event) => {
   if (event.button == 0) {
     mouseDownFn(model, group, event, (intersects) => {
-      if (fmType === 'fireDoor' && fireDoor) {
+      if (fhmType === 'fireDoor' && fireDoor) {
         fireDoor?.mousedownModel.call(fireDoor, intersects);
       }
-      if (fmType === 'fireDoorF' && fireDoorF) {
+      if (fhmType === 'fireDoorF' && fireDoorF) {
         fireDoorF?.mousedownModel.call(fireDoorF, intersects);
       }
+      if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
+        fireDoorSsl?.mousedownModel.call(fireDoorSsl, intersects);
+      }
+      if (fhmType === 'fireDoorRed' && fireDoorRed) {
+        fireDoorRed?.mousedownModel.call(fireDoorRed, intersects);
+      }
     });
     // console.log('摄像头控制信息', model.orbitControls, model.camera);
   }
 };
 
 export const play = (handlerState, flag?) => {
-  if (fmType === 'fireDoor' && fireDoor) {
+  if (fhmType === 'fireDoor' && fireDoor) {
     return fireDoor.play.call(fireDoor, handlerState, flag);
   }
-  if (fmType === 'fireDoorF' && fireDoorF) {
+  if (fhmType === 'fireDoorF' && fireDoorF) {
     return fireDoorF.play.call(fireDoorF, handlerState, flag);
   }
+  if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
+    return fireDoorSsl.play.call(fireDoorSsl, handlerState, flag);
+  }
+  if (fhmType === 'fireDoorRed' && fireDoorRed) {
+    return fireDoorRed.play.call(fireDoorRed, handlerState, flag);
+  }
 };
 
 // 切换风门类型
 export const setModelType = (type) => {
-  fmType = type;
+  // 重置动画
+  if (fhmType === 'fireDoor' && fireDoor) {
+    fireDoor.resetAnimate();
+  }
+  if (fhmType === 'fireDoorF' && fireDoorF) {
+    fireDoorF.resetAnimate();
+  }
+  if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
+    fireDoorSsl.resetAnimate();
+  }
+  if (fhmType === 'fireDoorRed' && fireDoorRed) {
+    fireDoorRed.resetAnimate();
+  }
+
+  fhmType = type;
+
+  const fhmConfigurations = {
+    fireDoor: {
+      render: fireDoor ? () => fireDoor.render() : null,
+      group: fireDoor ? fireDoor.group : null,
+      newP: { x: -654.2006991449887, y: 103.16181473511944, z: -30.348656073478562 },
+      newT: { x: -7.380506513422206, y: 56.36967052459397, z: -29.230675020846963 },
+    },
+    fireDoorF: {
+      render: fireDoorF ? () => fireDoorF.render() : null,
+      group: fireDoorF ? fireDoorF.group : null,
+      newP: { x: -655.0169729333649, y: 47.24181078408825, z: -9.781926649842067 },
+      newT: { x: -7.380506513422206, y: 47.24181078408821, z: -37.9244016972381 },
+    },
+    fireDoorSsl: {
+      render: fireDoorSsl ? () => fireDoorSsl.render() : null,
+      group: fireDoorSsl ? fireDoorSsl.group : null,
+      newP: { x: 342.74781900192056, y: 183.50210411099545, z: 451.0806333923029 },
+      newT: { x: 72.33938301176254, y: -35.03891296652319, z: -37.91742549963208 },
+    },
+    fireDoorRed: {
+      render: fireDoorRed ? () => fireDoorRed.render() : null,
+      group: fireDoorRed ? fireDoorRed.group : null,
+      newP: { x: 66.14, y: 52.98, z: 112.23 },
+      newT: { x: 6.049, y: 7.907, z: -25.566 },
+    },
+  };
+
+  if (type == 'fireDoor' || type == 'fireDoorF') {
+    model.orbitControls.maxPolarAngle = Math.PI / 2;
+    model.orbitControls.minPolarAngle = Math.PI / 3;
+    model.orbitControls.minDistance = 600;
+    model.orbitControls.maxDistance = 900;
+    model.orbitControls.update();
+  } else if (type == 'fireDoorRed' || type == 'fireDoorSsl') {
+    model.orbitControls.maxPolarAngle = Math.PI;
+    model.orbitControls.minPolarAngle = 0;
+    model.orbitControls.enableRotate = true;
+    model.orbitControls.minDistance = 0;
+    model.orbitControls.maxDistance = Infinity;
+    model.orbitControls.update();
+  }
+
+  const config = fhmConfigurations[fhmType];
+  const oldCameraPosition = { x: -1000, y: 100, z: 500 };
   return new Promise((resolve) => {
-    // 暂停风门1动画
-    if (fmType === 'fireDoor' && fireDoor && fireDoor.group) {
-      if (fireDoor.clipActionArr.door) {
-        fireDoor.clipActionArr.door.reset();
-        fireDoor.clipActionArr.door.time = 0.5;
-        fireDoor.clipActionArr.door.stop();
-      }
+    if (config && config.group) {
+      model.startAnimation = config.render;
+      group = config.group;
 
-      if (fireDoor.damperOpenMesh) fireDoor.damperOpenMesh.visible = false;
-      if (fireDoor.damperClosedMesh) fireDoor.damperClosedMesh.visible = true;
-      model.scene.remove(group);
-      model.startAnimation = fireDoor.render.bind(fireDoor);
-      group = fireDoor.group;
-      group.rotation.y = 0;
-      const oldCameraPosition = { x: -1000, y: 100, z: 500 };
-      setTimeout(async () => {
-        resolve(null);
-        model.scene.add(fireDoor.group);
-        await animateCamera(
-          oldCameraPosition,
-          { x: 0, y: 0, z: 0 },
-          { x: -654.2006991449887, y: 103.16181473511944, z: -30.348656073478562 },
-          { x: -7.380506513422206, y: 56.36967052459397, z: -29.230675020846963 },
-          model,
-          0.8
-        );
-      }, 300);
-    } else if (fmType === 'fireDoorF' && fireDoorF && fireDoorF.group) {
-      if (fireDoorF.clipActionArr.door) {
-        fireDoorF.clipActionArr.door.reset();
-        fireDoorF.clipActionArr.door.time = 0;
-        fireDoorF.clipActionArr.door.stop();
-      }
-      model.scene.remove(group);
-      model.startAnimation = fireDoorF.render.bind(fireDoorF);
-      group = fireDoorF.group;
-      group.rotation.y = 0;
-      const oldCameraPosition = { x: -1000, y: 100, z: 500 };
       setTimeout(async () => {
+        await animateCamera(oldCameraPosition, { x: 0, y: 0, z: 0 }, config.newP, config.newT, model);
+        model.scene?.add(config.group);
         resolve(null);
-        model.scene.add(fireDoorF.group);
-        await animateCamera(
-          oldCameraPosition,
-          { x: 0, y: 0, z: 0 },
-          { x: -655.0169729333649, y: 47.24181078408825, z: -9.781926649842067 },
-          { x: -7.380506513422206, y: 47.24181078408821, z: -37.9244016972381 },
-          model,
-          0.8
-        );
-      }, 300);
+      }, 1000);
+    } else {
+      resolve(null);
+      throw new Error(`Unsupported fhmType: ${fhmType}`);
     }
   });
 };
 
 export const initCameraCanvas = async (playerVal1) => {
-  if (fmType === 'fireDoor' && fireDoor) {
+  if (fhmType === 'fireDoor' && fireDoor) {
     return await fireDoor.initCamera.call(fireDoor, playerVal1);
-  } else if (fmType === 'fireDoorF' && fireDoorF) {
+  } else if (fhmType === 'fireDoorF' && fireDoorF) {
     return await fireDoorF.initCamera.call(fireDoorF, playerVal1);
+  } else if (fhmType === 'fireDoorSsl' && fireDoorSsl) {
+    return await fireDoorSsl.initCamera.call(fireDoorSsl, playerVal1);
+  } else if (fhmType === 'fireDoorRed' && fireDoorRed) {
+    return await fireDoorRed.initCamera.call(fireDoorRed, playerVal1);
   }
 };
-const setControls = () => {
-  if (model && model.orbitControls) {
-    model.orbitControls.maxPolarAngle = Math.PI / 2;
-    model.orbitControls.minPolarAngle = Math.PI / 3;
-    model.orbitControls.minDistance = 600;
-    model.orbitControls.maxDistance = 900;
-  }
+
+const loadModel = (code): Promise<any> => {
+  if (code === 'fireDoor') return import('./fireDoor.threejs.fire').then((r) => r.default);
+  if (code === 'fireDoorF') return import('./fireDoor.threejs.fireF').then((r) => r.default);
+  if (code === 'fireDoorSsl') return import('./fireDoor.threejs.ssl').then((r) => r.default);
+  if (code === 'fireDoorRed') return import('./fireDoor.threejs.fire.redGate').then((r) => r.default);
+  return import('./fireDoor.threejs.fire.redGate').then((r) => r.default);
 };
 
 export const mountedThree = () => {
@@ -135,13 +178,40 @@ export const mountedThree = () => {
     model.setEnvMap('test1.hdr');
     model.renderer.toneMappingExposure = 1.0;
     model.camera.position.set(100, 0, 1000);
-    fireDoor = new FireDoor(model);
-    fireDoor.mountedThree();
-
-    fireDoorF = new FireDoorF(model);
-    fireDoorF.mountedThree();
+    const dictCodes = getDictItemsByCode('fireDoorStyle');
+    if (dictCodes && dictCodes.length > 0) {
+      for (let i = 0; i < dictCodes.length; i++) {
+        const dict = dictCodes[i];
+        switch (dict.value) {
+          case 'fireDoor':
+            const FireDoor = await loadModel('fireDoor');
+            fireDoor = new FireDoor(model);
+            fireDoor.mountedThree();
+            break;
+          case 'fireDoorF':
+            const FireDoorF = await loadModel('fireDoorF');
+            fireDoorF = new FireDoorF(model);
+            fireDoorF.mountedThree();
+            break;
+          case 'fireDoorSsl':
+            const FireDoorSsl = await loadModel('fireDoorSsl');
+            fireDoorSsl = new FireDoorSsl(model);
+            fireDoorSsl.mountedThree();
+            break;
+          case 'fireDoorRed':
+            const FireDoorRed = await loadModel('fireDoorRed');
+            fireDoorRed = new FireDoorRed(model);
+            fireDoorRed.mountedThree();
+            break;
+        }
+      }
+      resolve(null);
+    } else {
+      const FireDoorRed = await loadModel('');
+      fireDoorRed = new FireDoorRed(model);
+      fireDoorRed.mountedThree();
+    }
     resolve(null);
-    setControls();
     model.animate();
     startAnimation();
   });
@@ -158,6 +228,13 @@ export const destroy = () => {
     model.isRender = false;
     if (fireDoor) fireDoor.destroy();
     fireDoor = null;
+    if (fireDoorF) fireDoorF.destroy();
+    fireDoorF = null;
+    if (fireDoorSsl) fireDoorSsl.destroy();
+    fireDoorSsl = null;
+    if (fireDoorRed) fireDoorRed.destroy();
+    fireDoorRed = null;
+    // @ts-ignore-next-line
     group = null;
     model.mixers = [];
     model.destroy();

+ 299 - 296
src/views/vent/monitorManager/fireDoorMonitor/index.vue

@@ -177,342 +177,345 @@
 </template>
 
 <script setup lang="ts">
-import { onBeforeUnmount, onUnmounted, onMounted, ref, reactive, nextTick, inject, unref } from 'vue';
-import MonitorTable from '../comment/MonitorTable.vue';
-import HistoryTable from '../comment/HistoryTable.vue';
-import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
-import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
-import HandleModal from './modal.vue';
-import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
-import { mountedThree, play, destroy, setModelType } from './fireDoor.threejs';
-import { deviceControlApi } from '/@/api/vent/index';
-import { message } from 'ant-design-vue';
-import { list, getTableList } from './fireDoor.api';
-import lodash from 'lodash';
-import { setDivHeight } from '/@/utils/event';
-import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
-import { useRouter } from 'vue-router';
-import { useModal } from '/@/components/Modal';
-import { useCamera } from '/@/hooks/system/useCamera';
-import { usePermission } from '/@/hooks/web/usePermission';
-import { getDictItems } from '/@/api/common/api';
+  import { onBeforeUnmount, onUnmounted, onMounted, ref, reactive, nextTick, inject, unref } from 'vue';
+  import MonitorTable from '../comment/MonitorTable.vue';
+  import HistoryTable from '../comment/HistoryTable.vue';
+  import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
+  import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
+  import HandleModal from './modal.vue';
+  import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
+  import { mountedThree, play, destroy, setModelType } from './fireDoor.threejs';
+  import { deviceControlApi } from '/@/api/vent/index';
+  import { message } from 'ant-design-vue';
+  import { list, getTableList } from './fireDoor.api';
+  import lodash from 'lodash';
+  import { setDivHeight } from '/@/utils/event';
+  import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
+  import { useRouter } from 'vue-router';
+  import { useModal } from '/@/components/Modal';
+  import { useCamera } from '/@/hooks/system/useCamera';
+  import { usePermission } from '/@/hooks/web/usePermission';
+  import { getDictItems } from '/@/api/common/api';
 
-const { hasPermission } = usePermission();
+  const { hasPermission } = usePermission();
 
-const globalConfig = inject('globalConfig');
+  const globalConfig = inject('globalConfig');
 
-const { currentRoute } = useRouter();
-const MonitorDataTable = ref();
-let contrlValue = '';
-const playerRef = ref();
-const deviceType = ref('door');
-// const deviceType = ref('firedoor');
-const activeKey = ref('1'); // tab
-const loading = ref(false);
+  const { currentRoute } = useRouter();
+  const MonitorDataTable = ref();
+  let contrlValue = '';
+  const playerRef = ref();
+  const deviceType = ref('gate');
+  // const deviceType = ref('firedoor');
+  const activeKey = ref('1'); // tab
+  const loading = ref(false);
 
-const scroll = reactive({
-  y: 230,
-});
-const modelList = ref<{ text: string; value: string }[]>([]);
-const doorIsOpen = ref(false); //前门是否开启
-const modalIsShow = ref<boolean>(false); // 是否显示模态框
-const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
-const modalType = ref(''); // 模态框内容显示类型,设备操作类型
+  const scroll = reactive({
+    y: 230,
+  });
+  const modelList = ref<{ text: string; value: string }[]>([]);
+  const doorIsOpen = ref(false); //前门是否开启
+  const modalIsShow = ref<boolean>(false); // 是否显示模态框
+  const modalTitle = ref(''); // 模态框标题显示内容,根据设备操作类型决定
+  const modalType = ref(''); // 模态框内容显示类型,设备操作类型
 
-const selectRowIndex = ref(-1); // 选中行
-const dataSource = ref([]);
+  const selectRowIndex = ref(-1); // 选中行
+  const dataSource = ref([]);
 
-const deviceBaseList = ref([]); // 设备基本信息
-const [registerModal, { openModal, closeModal }] = useModal();
+  const deviceBaseList = ref([]); // 设备基本信息
+  const [registerModal, { openModal, closeModal }] = useModal();
 
-const { getCamera, removeCamera } = useCamera();
+  const { getCamera, removeCamera } = useCamera();
 
-const tabChange = (activeKeyVal) => {
-  activeKey.value = activeKeyVal;
-  if (activeKeyVal == 1) {
-    nextTick(() => {
-      if (MonitorDataTable.value) MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
-    });
-  }
-};
+  const tabChange = (activeKeyVal) => {
+    activeKey.value = activeKeyVal;
+    if (activeKeyVal == 1) {
+      nextTick(() => {
+        if (MonitorDataTable.value) MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
+      });
+    }
+  };
 
-const initData = {
-  deviceID: '',
-  deviceType: '',
-  strname: '',
-  frontRearDP: '-', //压差
-  // sourcePressure: '-', //气源压力
-  runRoRecondition: null,
-  autoRoManual: null,
-  netStatus: '0', //通信状态
-  frontGateOpen: '0',
-  frontGateClose: '1',
-  rearGateOpen: '0',
-  rearGateClose: '1',
-  midGateOpen: '0',
-  midGateClose: '1',
-  fault: '气源压力超限',
-  masterComputer: 0,
-  frontGateOpenCtrl: false,
-  rearGateOpenCtrl: false,
-  cameras: [],
-};
+  const initData = {
+    deviceID: '',
+    deviceType: '',
+    strname: '',
+    frontRearDP: '-', //压差
+    // sourcePressure: '-', //气源压力
+    runRoRecondition: null,
+    autoRoManual: null,
+    netStatus: '0', //通信状态
+    frontGateOpen: '0',
+    frontGateClose: '1',
+    rearGateOpen: '0',
+    rearGateClose: '1',
+    midGateOpen: '0',
+    midGateClose: '1',
+    fault: '气源压力超限',
+    masterComputer: 0,
+    frontGateOpenCtrl: false,
+    rearGateOpenCtrl: false,
+    cameras: [],
+  };
 
-// 监测数据
-const selectData = reactive(lodash.cloneDeep(initData));
-function deviceEdit(e: Event, type: string, record) {
-  e.stopPropagation();
-  openModal(true, {
-    type,
-    deviceId: record['deviceID'],
-  });
-}
-// 获取设备基本信息列表
-function getDeviceBaseList() {
-  getTableList({ pageSize: 1000 }).then((res) => {
-    deviceBaseList.value = res.records;
-  });
-}
+  // 监测数据
+  const selectData = reactive(lodash.cloneDeep(initData));
+  function deviceEdit(e: Event, type: string, record) {
+    e.stopPropagation();
+    openModal(true, {
+      type,
+      deviceId: record['deviceID'],
+    });
+  }
+  // 获取设备基本信息列表
+  function getDeviceBaseList() {
+    getTableList({ pageSize: 1000 }).then((res) => {
+      deviceBaseList.value = res.records;
+    });
+  }
 
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-async function getMonitor(flag?) {
-  if (Object.prototype.toString.call(timer) === '[object Null]') {
-    timer = await setTimeout(
-      async () => {
-        const res = await list({ devicetype: deviceType.value, pagetype: 'normal' });
-        if (res.msgTxt && res.msgTxt[0]) {
-          dataSource.value = res.msgTxt[0].datalist || [];
-          dataSource.value.forEach((data: any) => {
-            const readData = data.readData;
-            data = Object.assign(data, readData);
-          });
-          if (dataSource.value.length > 0 && selectRowIndex.value == -1 && MonitorDataTable.value) {
-            // 初始打开页面
-            if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
-              MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
-            } else {
-              MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
+  // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  async function getMonitor(flag?) {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = await setTimeout(
+        async () => {
+          const res = await list({ devicetype: deviceType.value, pagetype: 'normal' });
+          if (res.msgTxt && res.msgTxt[0]) {
+            dataSource.value = res.msgTxt[0].datalist || [];
+            dataSource.value.forEach((data: any) => {
+              const readData = data.readData;
+              data = Object.assign(data, readData);
+            });
+            if (dataSource.value.length > 0 && selectRowIndex.value == -1 && MonitorDataTable.value) {
+              // 初始打开页面
+              if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
+                MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
+              } else {
+                MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
+              }
             }
+            Object.assign(selectData, dataSource.value[selectRowIndex.value]);
+            monitorAnimation(selectData);
+            if (timer) {
+              timer = null;
+            }
+            getMonitor();
           }
-          Object.assign(selectData, dataSource.value[selectRowIndex.value]);
-          monitorAnimation(selectData);
-          if (timer) {
-            timer = null;
-          }
-          getMonitor();
-        }
-      },
-      flag ? 0 : 1000
-    );
+        },
+        flag ? 0 : 1000
+      );
+    }
   }
-}
 
-// 切换检测数据
-async function getSelectRow(selectRow, index) {
-  if (!selectRow) return;
-  loading.value = true;
-  selectRowIndex.value = index;
-  const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
-  Object.assign(selectData, initData, selectRow, baseData);
-  doorDeviceState = 1; //记录设备状态,为了与下一次监测数据做比较
-  let type = 'fireDoor';
-  if (selectData.modelType == 'bd_qt') {
-    type = 'fireDoor';
-  } else if (selectData.modelType == 'bd_kj') {
-    type = 'fireDoorF';
-  }
-  await setModelType(type);
-  loading.value = false;
-  isdoorOpenRunning = true; //开关门动作是否在进行
-  await getCamera(selectRow.deviceID, playerRef.value);
-}
+  // 切换检测数据
+  async function getSelectRow(selectRow, index) {
+    if (!selectRow) return;
+    loading.value = true;
+    selectRowIndex.value = index;
+    const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
+    Object.assign(selectData, initData, selectRow, baseData);
+    doorDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+    isdoorOpenRunning = false; //开关门动作是否在进行
+    let type = 'fireDoorRed';
+    if (selectData.modelType == 'bd_qt') {
+      type = 'fireDoor';
+    } else if (selectData.modelType == 'bd_kj') {
+      type = 'fireDoorF';
+    }
+    await setModelType(type);
+    loading.value = false;
 
-function playAnimation(handlerState, data: any = null) {
-  const value = data;
-  switch (handlerState) {
-    case 1: // 打开前门
-      modalTitle.value = '打开';
-      modalType.value = '1';
-      modalIsShow.value = true;
-      break;
-    case 2: // 关闭前门
-      modalTitle.value = '关闭';
-      modalType.value = '2';
-      modalIsShow.value = true;
-      break;
-    case 7: // 控制模式切换
-      modalTitle.value = '控制模式切换';
-      modalType.value = '7';
-      modalIsShow.value = true;
-      break;
+    await getCamera(selectRow.deviceID, playerRef.value);
   }
 
-  if (globalConfig?.simulatedPassword) {
-    handleOK('', handlerState + '');
-  }
-  contrlValue = value;
-}
+  function playAnimation(handlerState, data: any = null) {
+    const value = data;
+    switch (handlerState) {
+      case 1: // 打开前门
+        modalTitle.value = '打开';
+        modalType.value = '1';
+        modalIsShow.value = true;
+        break;
+      case 2: // 关闭前门
+        modalTitle.value = '关闭';
+        modalType.value = '2';
+        modalIsShow.value = true;
+        break;
+      case 7: // 控制模式切换
+        modalTitle.value = '控制模式切换';
+        modalType.value = '7';
+        modalIsShow.value = true;
+        break;
+    }
 
-function handleOK(passWord, handlerState) {
-  if (!passWord && !globalConfig?.simulatedPassword) {
-    message.warning('请输入密码');
-    return;
-  }
-  if (isOpenRunning) {
-    return;
-  }
-  const data = {
-    deviceid: selectData.deviceID,
-    devicetype: selectData.deviceType,
-    paramcode: '',
-    value: contrlValue,
-    password: passWord || globalConfig?.simulatedPassword,
-    masterComputer: selectData.masterComputer,
-  };
-  switch (handlerState) {
-    case '1': // 打开前门
-      if (selectData.doorOpen == '0' && selectData.doorClose == '1') {
-        data.paramcode = 'frontGateOpen_S';
-      }
-      break;
-    case '2': // 关闭前门
-      if (selectData.doorOpen == '1' && selectData.doorClose == '0') {
-        data.paramcode = 'frontGateClose_S';
-      }
-      break;
-    case '7': // 远程与就地
-      data.paramcode = 'autoRoManualControl';
-      data.value = selectData.contrlMod != 'loopCtrl' ? contrlValue : '';
-      selectData.autoRoManual = null;
+    if (globalConfig?.simulatedPassword) {
+      handleOK('', handlerState + '');
+    }
+    contrlValue = value;
   }
 
-  if (data.paramcode) {
-    deviceControlApi(data).then((res) => {
-      // 模拟时开启
-      if (res.success) {
-        modalIsShow.value = false;
-        if (globalConfig.History_Type == 'remote') {
-          message.success('指令已下发至生产管控平台成功!');
+  function handleOK(passWord, handlerState) {
+    if (!passWord && !globalConfig?.simulatedPassword) {
+      message.warning('请输入密码');
+      return;
+    }
+    if (isOpenRunning) {
+      return;
+    }
+    const data = {
+      deviceid: selectData.deviceID,
+      devicetype: selectData.deviceType,
+      paramcode: '',
+      value: contrlValue,
+      password: passWord || globalConfig?.simulatedPassword,
+      masterComputer: selectData.masterComputer,
+    };
+    switch (handlerState) {
+      case '1': // 打开前门
+        if (selectData.doorOpen == '0' && selectData.doorClose == '1') {
+          data.paramcode = 'frontGateOpen_S';
+        }
+        break;
+      case '2': // 关闭前门
+        if (selectData.doorOpen == '1' && selectData.doorClose == '0') {
+          data.paramcode = 'frontGateClose_S';
+        }
+        break;
+      case '7': // 远程与就地
+        data.paramcode = 'autoRoManualControl';
+        data.value = selectData.contrlMod != 'loopCtrl' ? contrlValue : '';
+        selectData.autoRoManual = null;
+    }
+
+    if (data.paramcode) {
+      deviceControlApi(data).then((res) => {
+        // 模拟时开启
+        if (res.success) {
+          modalIsShow.value = false;
+          if (globalConfig.History_Type == 'remote') {
+            message.success('指令已下发至生产管控平台成功!');
+          } else {
+            message.success('指令已下发成功!');
+          }
         } else {
-          message.success('指令已下发成功!');
+          message.error(res.message);
         }
-      } else {
-        message.error(res.message);
-      }
-    });
-  }
-}
-let isOpenRunning = false; //开关门动作是否在进行
-/** 开关门动画调用 */
-let isdoorOpenRunning = false; //开关门动作是否在进行
-// let isMidCloseRunning = false; //中间门动作是否在进行
-// 0 关闭 1 正在打开 2 打开 3正在关闭
-let doorDeviceState = 1; //记录设备状态,为了与下一次监测数据做比较
-function monitorAnimation(selectData) {
-  const timeScale = 0.005;
-  // 打开
-  if (selectData.frontGateOpen == '1' && !isdoorOpenRunning) {
-    isdoorOpenRunning = true;
-    if (doorDeviceState != 1) {
-      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
-      play(1, timeScale);
-      doorDeviceState = 1;
-      doorIsOpen.value = true;
+      });
     }
   }
-  // 关闭
-  if (selectData.frontGateOpen == '0' && isdoorOpenRunning) {
-    isdoorOpenRunning = false;
-    if (doorDeviceState != 0) {
-      // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
-      play(2, timeScale);
-      doorDeviceState = 0;
-      doorIsOpen.value = false;
+  let isOpenRunning = false; //开关门动作是否在进行
+  /** 开关门动画调用 */
+  let isdoorOpenRunning = false; //开关门动作是否在进行
+  // let isMidCloseRunning = false; //中间门动作是否在进行
+  // 0 关闭 1 正在打开 2 打开 3正在关闭
+  let doorDeviceState = 0; //记录设备状态,为了与下一次监测数据做比较
+  function monitorAnimation(selectData) {
+    const timeScale = 0.005;
+    // 打开
+    if (selectData.frontGateOpen == '1' && !isdoorOpenRunning) {
+      isdoorOpenRunning = true;
+      if (doorDeviceState != 1) {
+        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
+        play(1, timeScale);
+        debugger;
+        doorDeviceState = 1;
+        doorIsOpen.value = true;
+      }
+    }
+    // 关闭
+    if (selectData.frontGateOpen == '0' && isdoorOpenRunning) {
+      isdoorOpenRunning = false;
+      if (doorDeviceState != 0) {
+        // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(1, timeScale) : play(1);
+        play(2, timeScale);
+        debugger;
+        doorDeviceState = 0;
+        doorIsOpen.value = false;
+      }
     }
-  }
 
-  // if (selectData.frontGateClose == '1' && selectData.frontGateOpen == '0' && isFrontOpenRunning) {
-  //   isFrontOpenRunning = false;
-  //   if (frontDeviceState != 0) {
-  //     // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(2, timeScale) : play(2);
-  //     play(2, timeScale);
-  //     frontDeviceState = 0;
-  //     frontDoorIsOpen.value = false;
-  //     // backDoorIsOpen.value = false
-  //   }
-  // }
-}
+    // if (selectData.frontGateClose == '1' && selectData.frontGateOpen == '0' && isFrontOpenRunning) {
+    //   isFrontOpenRunning = false;
+    //   if (frontDeviceState != 0) {
+    //     // import.meta.env.VITE_GLOB_IS_SIMULATE ? play(2, timeScale) : play(2);
+    //     play(2, timeScale);
+    //     frontDeviceState = 0;
+    //     frontDoorIsOpen.value = false;
+    //     // backDoorIsOpen.value = false
+    //   }
+    // }
+  }
 
-function handleCancel() {
-  modalIsShow.value = false;
-  modalTitle.value = '';
-  modalType.value = '';
-  selectData.autoRoManual = null;
-}
+  function handleCancel() {
+    modalIsShow.value = false;
+    modalTitle.value = '';
+    modalType.value = '';
+    selectData.autoRoManual = null;
+  }
 
-onMounted(async () => {
-  const { query } = unref(currentRoute);
-  if (query['deviceType']) deviceType.value = query['deviceType'] as string;
-  modelList.value = await getDictItems('fireDoorModel');
-  loading.value = true;
-  mountedThree().then(async () => {
-    await getMonitor(true);
-    loading.value = false;
+  onMounted(async () => {
+    const { query } = unref(currentRoute);
+    if (query['deviceType']) deviceType.value = query['deviceType'] as string;
+    modelList.value = await getDictItems('fireDoorModel');
+    loading.value = true;
+    mountedThree().then(async () => {
+      await getMonitor(true);
+      loading.value = false;
+    });
   });
-});
 
-onBeforeUnmount(() => {
-  getDeviceBaseList();
-});
+  onBeforeUnmount(() => {
+    getDeviceBaseList();
+  });
 
-onUnmounted(() => {
-  removeCamera();
-  if (timer) {
-    clearTimeout(timer);
-    timer = undefined;
-  }
-  destroy();
-});
+  onUnmounted(() => {
+    removeCamera();
+    if (timer) {
+      clearTimeout(timer);
+      timer = undefined;
+    }
+    destroy();
+  });
 </script>
 ,
 <style lang="less" scoped>
-@import '/@/design/vent/modal.less';
-.scene-box {
-  .bottom-tabs-box {
-    height: 300px;
+  @import '/@/design/vent/modal.less';
+  .scene-box {
+    .bottom-tabs-box {
+      height: 300px;
+    }
   }
-}
-.button-box {
-  border: none !important;
-  height: 34px !important;
+  .button-box {
+    border: none !important;
+    height: 34px !important;
 
-  &:hover {
-    background: linear-gradient(#2cd1ff55, #1eb0ff55) !important;
-  }
+    &:hover {
+      background: linear-gradient(#2cd1ff55, #1eb0ff55) !important;
+    }
 
-  &::before {
-    height: 27px !important;
-    background: linear-gradient(#1fa6cb, #127cb5) !important;
-  }
+    &::before {
+      height: 27px !important;
+      background: linear-gradient(#1fa6cb, #127cb5) !important;
+    }
 
-  &::after {
-    top: 35px !important;
+    &::after {
+      top: 35px !important;
+    }
   }
-}
 
-:deep(.@{ventSpace}-tabs-tabpane-active) {
-  height: 100%;
-}
+  :deep(.@{ventSpace}-tabs-tabpane-active) {
+    height: 100%;
+  }
 
-::-webkit-scrollbar-thumb {
-  -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
-  background: #4288a444;
-}
-:deep(.zxm-radio-disabled + span) {
-  color: #fff !important;
-}
-:deep(.zxm-radio-disabled .zxm-radio-inner::after) {
-  background-color: #127cb5 !important;
-}
+  ::-webkit-scrollbar-thumb {
+    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+    background: #4288a444;
+  }
+  :deep(.zxm-radio-disabled + span) {
+    color: #fff !important;
+  }
+  :deep(.zxm-radio-disabled .zxm-radio-inner::after) {
+    background-color: #127cb5 !important;
+  }
 </style>

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

@@ -1,18 +1,18 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
-import Fm1 from './gate.threejs.yy';
-import Fm3 from './gate.threejs.qd';
+// import Fm1 from './gate.threejs.yy';
+// import Fm3 from './gate.threejs.qd';
 import FmXR from './gate.threejs.xr';
-import Fm2 from './gate.threejs.three';
-import FmTwoSs from './gate.threejs.two.ss';
-import FmThreeTl from './gate.threejs.three.tl';
-import FmDc from './gate.threejs.window';
-import FmDcHJG from './gate.threejs.window.hjg';
-import FmDcZHQ from './gate.threejs.window.zhq';
-import FmHsw3 from './gate.threejs.three.hsw';
-import FmYjXr from './gate.threejs.two.yj'; // 窑街行人
-import FmYj from './gate.threejs.yj'; // 窑街
-import FmSp1 from './gate.threejs.one.sp';
+// import Fm2 from './gate.threejs.three';
+// import FmTwoSs from './gate.threejs.two.ss';
+// import FmThreeTl from './gate.threejs.three.tl';
+// import FmDc from './gate.threejs.window';
+// import FmDcHJG from './gate.threejs.window.hjg';
+// import FmDcZHQ from './gate.threejs.window.zhq';
+// import FmHsw3 from './gate.threejs.three.hsw';
+// import FmYjXr from './gate.threejs.two.yj'; // 窑街行人
+// import FmYj from './gate.threejs.yj'; // 窑街
+// import FmSp1 from './gate.threejs.one.sp';
 import { animateCamera } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
 import { getDictItemsByCode } from '/@/utils/dict';

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

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

文件差異過大導致無法顯示
+ 699 - 0
src/views/vent/monitorManager/mainFanMonitor/components/mainFanSVG.vue


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

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

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

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

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

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

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

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

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

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

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

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

+ 725 - 729
src/views/vent/monitorManager/windrectMonitor/index.vue

@@ -84,7 +84,7 @@
               </template>
             </MonitorTable>
           </a-tab-pane>
-          <a-tab-pane key="2" tab="监测曲线图" force-render>
+          <a-tab-pane v-if="hasPermission('windrect:chartMonitor')" key="2" tab="监测曲线图" force-render>
             <div class="tab-item" style="height: 280px" v-if="activeKey === '2'">
               <DeviceEcharts
                 chartsColumnsType="windrect_chart"
@@ -110,7 +110,7 @@
           <a-tab-pane v-if="hasPermission('windrect:result')" key="6" tab="测风结果">
             <ResultTable v-if="activeKey === '6'" deviceType="windrect_list" :scroll="scroll" />
           </a-tab-pane>
-          <a-tab-pane v-if="sysOrgCode != 'xjttzhqmk'" key="7" tab="报警次数统计">
+          <a-tab-pane v-if="hasPermission('windrect:alarmNum')" key="7" tab="报警次数统计">
             <div class="tab-item" v-if="activeKey === '7'">
               <AlarmNumTable columns-type="alarmNum" :device-type="deviceType" designScope="alarm-history" :scroll="280" />
             </div>
@@ -148,813 +148,809 @@
 </template>
 
 <script setup lang="ts">
-  import DeviceEcharts from '../comment/DeviceEcharts.vue';
-  import { unref, onBeforeMount, ref, onMounted, onUnmounted, reactive, toRaw, nextTick, inject, shallowRef } from 'vue';
-  import { BasicModal, useModalInner } from '/@/components/Modal';
-  import MonitorTable from '../comment/MonitorTable.vue';
-  import ModalTable from './components/modalTable.vue';
-  import HandleModal from './components/modal.vue';
-  import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
-  import ResultTable from './components/resultTable.vue';
-  import HistoryTable from '../comment/HistoryTable.vue';
-  import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
-  import AlarmNumTable from '../comment/AlarmNumTable.vue';
-  import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
-  import { deviceControlApi } from '/@/api/vent/index';
-  import { mountedThree, destroy, addMonitorText, play, setModelType, playCamera } from './windrect.threejs';
-  import { list, pathList, deviceList, testWind, exportXls, resetWind, getRegulation } from './windrect.api';
-  import { message, Progress } from 'ant-design-vue';
-  import { chartsColumns, chartsColumnsHistory, option } from './windrect.data';
-  import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
-  import { setDivHeight } from '/@/utils/event';
-  import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
-  import { useRouter } from 'vue-router';
-  import { useModal } from '/@/components/Modal';
-  import { useCamera } from '/@/hooks/system/useCamera';
-  import { usePermission } from '/@/hooks/web/usePermission';
-  import { useGlobSetting } from '/@/hooks/setting';
-  import { device } from '../../gas/gasPipeNet/gasPipeNet.api';
-  import { getModelComponent } from './windrect.data';
-  const { hasPermission } = usePermission();
-
-  const globalConfig = inject<any>('globalConfig');
-
-  const { sysOrgCode } = useGlobSetting();
-  const { currentRoute } = useRouter();
-  const modelRef = ref();
-  /** 模型对应的组件,根据实际情况分为二维三维 */
-  let modelComponent = shallowRef(getModelComponent(globalConfig.is2DModel));
-
-  const MonitorDataTable = ref();
-  const scroll = reactive({
-    y: 230,
-  });
-  const modalType = ref('');
-  const modalIsShow = ref(false);
-  const modalTable = ref();
-  const runNum = ref(5); //设备运行数量
-  const criticalPathList = ref([]);
-  const playerRef = ref();
-  const activeKey = ref('1');
-  const loading = ref(false);
-  // 默认初始是第一行
-  const selectRowIndex = ref(-1);
-  // 监测数据
-  const selectData = reactive({
-    deviceID: '',
-    deviceType: '',
-    strname: '',
-    dataDh: '-', //压差
-    dataDtestq: '-', //测试风量
-    // sourcePressure: '-', //气源压力
-    dataDequivalarea: '-',
-    netStatus: '0', //通信状态
-    fault: '气源压力超限',
-    sign: -1,
-    sensorRight: 0,
-    sensorMiddle: 1,
-    sensorLeft: 0,
-  });
-  const deviceType = ref('windrect');
-  const deviceId = ref('');
-  const chartsColumnArr = getTableHeaderColumns('windrect_chart');
-  const chartsColumnList = ref(chartsColumnArr.length > 0 ? chartsColumnArr : chartsColumns);
-
-  // const dataSource = computed(() => {
-  //   const data = [...getRecordList()] || [];
-  //   Object.assign(selectData, toRaw(data[selectRowIndex.value]));
-  //   addMonitorText(selectData);
-  //   return data;
-  // });
-
-  const dataSource = ref([]);
-  const [regModal, { openModal }] = useModal();
-
-  const { getCamera, removeCamera } = useCamera();
-  const tabChange = (activeKeyVal) => {
-    activeKey.value = activeKeyVal;
-    if (activeKeyVal == 1) {
-      nextTick(() => {
-        MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
-      });
-    }
-  };
-
-  // 设备数据
-  const controlType = ref(1);
-  //表单赋值
-  const [registerModal, { setModalProps, closeModal }] = useModalInner();
-
-  // https获取监测数据
-  let timer: null | NodeJS.Timeout = null;
-  // function getMonitor(flag?) {
-  //   if (Object.prototype.toString.call(timer) === '[object Null]') {
-  //     timer = setTimeout(
-  //       () => {
-  //         list({ devicetype: deviceType.value, pagetype: 'normal' }).then((res) => {
-  //           if (res && res.msgTxt[0]) {
-  //             // dataSource.value = res.msgTxt[0].datalist || [];
-  //             const getData = res.msgTxt[0].datalist || [];
-  //             getData.forEach((data) => {
-  //               if (data.regulation) {
-  //                 getRegulationList(data.regulation);
-  //               }
-  //             });
-  //             dataSource.value = getData;
-  //             if (dataSource.value.length > 0) {
-  //               dataSource.value.forEach((data: any) => {
-  //                 const readData = data.readData;
-  //                 data = Object.assign(data, readData);
-  //               });
-  //               if (dataSource.value.length > 0 && selectRowIndex.value == -1) {
-  //                 // 初始打开页面
-  //                 if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
-  //                   MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
-  //                 } else {
-  //                   MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
-  //                 }
-  //               }
-  //               const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
-  //               Object.assign(selectData, data);
-  //               addMonitorText(selectData);
-
-  //               palyAnimation(selectData);
-  //             }
-  //           }
-  //           if (timer) {
-  //             timer = null;
-  //           }
-  //           getMonitor();
-  //         });
-  //       },
-  //       flag ? 0 : 1000
-  //     );
-  //   }
-  // }
-  // function getRegulationList(data) {
-  //   getRegulation().then((res) => {
-  //     if (res) {
-  //       const regulation = res.find((item) => item.id == data);
-  //       data.regulation = regulation;
-  //       data.fmin = data.regulation.fmin;
-  //       data.fmax = data.regulation.fmax;
-  //     }
-  //   });
-  // }
-  // 缓存
-  let allRegulations: any[] | null = null;
-
-  async function getMonitor(flag?: boolean) {
-    if (timer === null) {
-      timer = setTimeout(
-        async () => {
-          try {
-            // 1. 获取监控列表数据
-            const res = await list({
-              devicetype: deviceType.value,
-              pagetype: 'normal',
-            });
-            if (res?.msgTxt[0]) {
-              const rawData = res.msgTxt[0].datalist || [];
-              const processedData = [...rawData];
-
-              // 首次请求获取去所有regulation数据
-              if (allRegulations === null) {
-                const regulationRes = await getRegulation({
-                  deviceKind: deviceType.value,
-                });
-                allRegulations = regulationRes || [];
-              }
-              // 根据id创建一个映射表
-              const regulationMap = new Map();
-              allRegulations.forEach((reg) => {
-                regulationMap.set(reg.id, reg);
+import DeviceEcharts from '../comment/DeviceEcharts.vue';
+import { unref, onBeforeMount, ref, onMounted, onUnmounted, reactive, toRaw, nextTick, inject, shallowRef } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import MonitorTable from '../comment/MonitorTable.vue';
+import ModalTable from './components/modalTable.vue';
+import HandleModal from './components/modal.vue';
+import DeviceBaseInfo from '../comment/components/DeviceBaseInfo.vue';
+import ResultTable from './components/resultTable.vue';
+import HistoryTable from '../comment/HistoryTable.vue';
+import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
+import AlarmNumTable from '../comment/AlarmNumTable.vue';
+import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
+import { deviceControlApi } from '/@/api/vent/index';
+import { mountedThree, destroy, addMonitorText, play, setModelType, playCamera } from './windrect.threejs';
+import { list, pathList, deviceList, testWind, exportXls, resetWind, getRegulation } from './windrect.api';
+import { message, Progress } from 'ant-design-vue';
+import { chartsColumns, chartsColumnsHistory, option } from './windrect.data';
+import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
+import { setDivHeight } from '/@/utils/event';
+import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
+import { useRouter } from 'vue-router';
+import { useModal } from '/@/components/Modal';
+import { useCamera } from '/@/hooks/system/useCamera';
+import { usePermission } from '/@/hooks/web/usePermission';
+import { useGlobSetting } from '/@/hooks/setting';
+import { device } from '../../gas/gasPipeNet/gasPipeNet.api';
+import { getModelComponent } from './windrect.data';
+const { hasPermission } = usePermission();
+
+const globalConfig = inject<any>('globalConfig');
+
+const { sysOrgCode } = useGlobSetting();
+const { currentRoute } = useRouter();
+const modelRef = ref();
+/** 模型对应的组件,根据实际情况分为二维三维 */
+let modelComponent = shallowRef(getModelComponent(globalConfig.is2DModel));
+
+const MonitorDataTable = ref();
+const scroll = reactive({
+  y: 230,
+});
+const modalType = ref('');
+const modalIsShow = ref(false);
+const modalTable = ref();
+const runNum = ref(5); //设备运行数量
+const criticalPathList = ref([]);
+const playerRef = ref();
+const activeKey = ref('1');
+const loading = ref(false);
+// 默认初始是第一行
+const selectRowIndex = ref(-1);
+// 监测数据
+const selectData = reactive({
+  deviceID: '',
+  deviceType: '',
+  strname: '',
+  dataDh: '-', //压差
+  dataDtestq: '-', //测试风量
+  // sourcePressure: '-', //气源压力
+  dataDequivalarea: '-',
+  netStatus: '0', //通信状态
+  fault: '气源压力超限',
+  sign: -1,
+  sensorRight: 0,
+  sensorMiddle: 1,
+  sensorLeft: 0,
+});
+const deviceType = ref('windrect');
+const deviceId = ref('');
+const chartsColumnArr = getTableHeaderColumns('windrect_chart');
+const chartsColumnList = ref(chartsColumnArr.length > 0 ? chartsColumnArr : chartsColumns);
+
+// const dataSource = computed(() => {
+//   const data = [...getRecordList()] || [];
+//   Object.assign(selectData, toRaw(data[selectRowIndex.value]));
+//   addMonitorText(selectData);
+//   return data;
+// });
+
+const dataSource = ref([]);
+const [regModal, { openModal }] = useModal();
+
+const { getCamera, removeCamera } = useCamera();
+const tabChange = (activeKeyVal) => {
+  activeKey.value = activeKeyVal;
+  if (activeKeyVal == 1) {
+    nextTick(() => {
+      MonitorDataTable.value.setSelectedRowKeys([selectData.deviceID]);
+    });
+  }
+};
+
+// 设备数据
+const controlType = ref(1);
+//表单赋值
+const [registerModal, { setModalProps, closeModal }] = useModalInner();
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+// function getMonitor(flag?) {
+//   if (Object.prototype.toString.call(timer) === '[object Null]') {
+//     timer = setTimeout(
+//       () => {
+//         list({ devicetype: deviceType.value, pagetype: 'normal' }).then((res) => {
+//           if (res && res.msgTxt[0]) {
+//             // dataSource.value = res.msgTxt[0].datalist || [];
+//             const getData = res.msgTxt[0].datalist || [];
+//             getData.forEach((data) => {
+//               if (data.regulation) {
+//                 getRegulationList(data.regulation);
+//               }
+//             });
+//             dataSource.value = getData;
+//             if (dataSource.value.length > 0) {
+//               dataSource.value.forEach((data: any) => {
+//                 const readData = data.readData;
+//                 data = Object.assign(data, readData);
+//               });
+//               if (dataSource.value.length > 0 && selectRowIndex.value == -1) {
+//                 // 初始打开页面
+//                 if (currentRoute.value && currentRoute.value['query'] && currentRoute.value['query']['id']) {
+//                   MonitorDataTable.value.setSelectedRowKeys([currentRoute.value['query']['id']]);
+//                 } else {
+//                   MonitorDataTable.value.setSelectedRowKeys([dataSource.value[0]['deviceID']]);
+//                 }
+//               }
+//               const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
+//               Object.assign(selectData, data);
+//               addMonitorText(selectData);
+
+//               palyAnimation(selectData);
+//             }
+//           }
+//           if (timer) {
+//             timer = null;
+//           }
+//           getMonitor();
+//         });
+//       },
+//       flag ? 0 : 1000
+//     );
+//   }
+// }
+// function getRegulationList(data) {
+//   getRegulation().then((res) => {
+//     if (res) {
+//       const regulation = res.find((item) => item.id == data);
+//       data.regulation = regulation;
+//       data.fmin = data.regulation.fmin;
+//       data.fmax = data.regulation.fmax;
+//     }
+//   });
+// }
+// 缓存
+let allRegulations: any[] | null = null;
+
+async function getMonitor(flag?: boolean) {
+  if (timer === null) {
+    timer = setTimeout(
+      async () => {
+        try {
+          // 1. 获取监控列表数据
+          const res = await list({
+            devicetype: deviceType.value,
+            pagetype: 'normal',
+          });
+          if (res?.msgTxt[0]) {
+            const rawData = res.msgTxt[0].datalist || [];
+            const processedData = [...rawData];
+
+            // 首次请求获取去所有regulation数据
+            if (allRegulations === null) {
+              const regulationRes = await getRegulation({
+                deviceKind: deviceType.value,
               });
-              // 对regulation字段进行替换
-              processedData.forEach((data) => {
-                if (data.regulation) {
-                  const reg = regulationMap.get(data.regulation);
-                  if (reg) {
-                    data.regulation = reg; // 替换为完整对象
-                    data.fmin = reg.fmin;
-                    data.fmax = reg.fmax;
-                  }
+              allRegulations = regulationRes || [];
+            }
+            // 根据id创建一个映射表
+            const regulationMap = new Map();
+            allRegulations.forEach((reg) => {
+              regulationMap.set(reg.id, reg);
+            });
+            // 对regulation字段进行替换
+            processedData.forEach((data) => {
+              if (data.regulation) {
+                const reg = regulationMap.get(data.regulation);
+                if (reg) {
+                  data.regulation = reg; // 替换为完整对象
+                  data.fmin = reg.fmin;
+                  data.fmax = reg.fmax;
                 }
-              });
-              dataSource.value = processedData;
-              if (dataSource.value.length > 0) {
-                await processReadData(processedData);
-                await handleInitialSelection();
               }
+            });
+            dataSource.value = processedData;
+            if (dataSource.value.length > 0) {
+              await processReadData(processedData);
+              await handleInitialSelection();
             }
-          } catch (error) {
-            console.error('Error', error);
-          } finally {
-            timer = null;
-            getMonitor(flag);
           }
-        },
-        flag ? 0 : 1000
-      );
-    }
+        } catch (error) {
+          console.error('Error', error);
+        } finally {
+          timer = null;
+          getMonitor();
+        }
+      },
+      flag ? 0 : 1000
+    );
   }
-
-  // async function getRegulationList(regulationId: string, data: any) {
-  //   const res = await getRegulation();
-  //   if (res) {
-  //     const regulation = res.find((item) => item.id === regulationId);
-  //     if (regulation) {
-  //       data.regulation = regulation;
-  //       data.fmin = regulation.fmin;
-  //       data.fmax = regulation.fmax;
-  //     }
-  //   }
-  // }
-
-  async function processReadData(data: any[]) {
-    const promises = data
-      .filter((item) => item.readData)
-      .map(async (item) => {
-        item.readData && Object.assign(item, item.readData);
-      });
-    await Promise.all(promises);
+}
+
+// async function getRegulationList(regulationId: string, data: any) {
+//   const res = await getRegulation();
+//   if (res) {
+//     const regulation = res.find((item) => item.id === regulationId);
+//     if (regulation) {
+//       data.regulation = regulation;
+//       data.fmin = regulation.fmin;
+//       data.fmax = regulation.fmax;
+//     }
+//   }
+// }
+
+async function processReadData(data: any[]) {
+  const promises = data
+    .filter((item) => item.readData)
+    .map(async (item) => {
+      item.readData && Object.assign(item, item.readData);
+    });
+  await Promise.all(promises);
+}
+
+async function handleInitialSelection() {
+  if (dataSource.value.length > 0) {
+    const selectedData = toRaw(dataSource.value[selectRowIndex.value]);
+    Object.assign(selectData, selectedData);
+    addMonitorText(selectData);
+    if (selectedData) palyAnimation(selectedData);
   }
-
-  async function handleInitialSelection() {
-    if (dataSource.value.length > 0) {
-      const selectedData = toRaw(dataSource.value[selectRowIndex.value]);
-      Object.assign(selectData, selectedData);
-      addMonitorText(selectData);
-      if (selectedData) palyAnimation(selectedData);
+}
+let deviceRunState = '',
+  tanTouRunState = '';
+// 根据3个点位分别执行动画
+function palyAnimation(selectData) {
+  if (selectData.deviceType == 'windrect_normal') {
+    if (selectData['apparatusRun'] == 1) {
+      const flag = selectData.sign == '0' ? 'up' : selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : null;
+      if (flag) play(flag);
+    } else {
+      const flag = selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : null;
+      if (flag) play(flag, true);
     }
   }
-  let deviceRunState = '',
-    tanTouRunState = '';
-  // 根据3个点位分别执行动画
-  function palyAnimation(selectData) {
-    if (selectData.deviceType == 'windrect_normal') {
-      if (selectData['apparatusRun'] == 1) {
-        const flag = selectData.sign == '0' ? 'up' : selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : null;
-        if (flag) play(flag);
-      } else {
-        const flag = selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : null;
-        if (flag) play(flag, true);
-      }
-    }
-    // 运行中是0,运行到达是1
-    if (selectData.deviceType == 'windrect_rect_single') {
-      if (selectData['apparatusRun'] == 1) {
-        // 镜头指向横杆
-        // if(!deviceRunState && !tanTouRunState)playCamera('start')
-        // 正在执行或是开始执行
-
-        //开始执行时,
-        // selectData['poleIncipient'] == 1 selectData.sensorMiddle == 1 代表可是执行 或是 执行结束
-
-        // 1. selectData['poleIncipient'] == 1 selectData.sensorMiddle == 1, 执行 play('up', true),play('middle', true)
-        // 2. 探头左移play('left')
-        // 3. 探头右移play('right')
-        // 4. 横杆向中位移动,探头在右边
-        // 5. 探头移到中间play('middle')
-        // 6. 探头移到左边play('left')
-        // 7. 横杆向低位移动,探头在左边
-        // 8. 探头移到中间play('middle')
-        // 9. 探头右移play('right')
-        // 10. 测风结束,探头移到中间play('middle'),横杆向高位移动
-        if (selectData['poleIncipient'] == 1) {
-          // 横杆在高位,开始执行 或是 执行结束
-          if (selectData.sensorMiddle == 1 && !deviceRunState && !tanTouRunState) {
-            // 1. 开始执行
-            deviceRunState = 'up';
-            tanTouRunState = 'middle';
-            play('up', true);
-            play('middle', true);
-          }
-          if (deviceRunState == 'up-m') {
-            play('up', true);
-            play('middle', true);
-            deviceRunState = '';
-            tanTouRunState = '';
-            playCamera('end');
-          }
-          // 初始已经在运行
+  // 运行中是0,运行到达是1
+  if (selectData.deviceType == 'windrect_rect_single') {
+    if (selectData['apparatusRun'] == 1) {
+      // 镜头指向横杆
+      // if(!deviceRunState && !tanTouRunState)playCamera('start')
+      // 正在执行或是开始执行
+
+      //开始执行时,
+      // selectData['poleIncipient'] == 1 selectData.sensorMiddle == 1 代表可是执行 或是 执行结束
+
+      // 1. selectData['poleIncipient'] == 1 selectData.sensorMiddle == 1, 执行 play('up', true),play('middle', true)
+      // 2. 探头左移play('left')
+      // 3. 探头右移play('right')
+      // 4. 横杆向中位移动,探头在右边
+      // 5. 探头移到中间play('middle')
+      // 6. 探头移到左边play('left')
+      // 7. 横杆向低位移动,探头在左边
+      // 8. 探头移到中间play('middle')
+      // 9. 探头右移play('right')
+      // 10. 测风结束,探头移到中间play('middle'),横杆向高位移动
+      if (selectData['poleIncipient'] == 1) {
+        // 横杆在高位,开始执行 或是 执行结束
+        if (selectData.sensorMiddle == 1 && !deviceRunState && !tanTouRunState) {
+          // 1. 开始执行
+          deviceRunState = 'up';
+          tanTouRunState = 'middle';
+          play('up', true);
+          play('middle', true);
+        }
+        if (deviceRunState == 'up-m') {
+          play('up', true);
+          play('middle', true);
+          deviceRunState = '';
+          tanTouRunState = '';
+          playCamera('end');
+        }
+        // 初始已经在运行
 
-          if (selectData.sensorLeft == '0' && selectData.sensorMiddle == '0' && selectData.sensorRight == '0') {
-            //2.探头左移play('left')
-            if (tanTouRunState == 'middle') {
-              tanTouRunState = 'left-m';
-              play('left');
-            }
-            //3. 探头右移play('right')
-            if (tanTouRunState == 'left') {
-              tanTouRunState = 'right-m';
-              play('right');
-            }
-          }
-          if (selectData.sensorLeft == 1) {
-            tanTouRunState = 'left';
-            if (!tanTouRunState || tanTouRunState == 'left-m') {
-              play('left', true);
-            }
-          }
-          if (selectData.sensorRight == 1) {
-            tanTouRunState = 'right';
-            if (!tanTouRunState || tanTouRunState == 'right-m') {
-              play('right', true);
-            }
+        if (selectData.sensorLeft == '0' && selectData.sensorMiddle == '0' && selectData.sensorRight == '0') {
+          //2.探头左移play('left')
+          if (tanTouRunState == 'middle') {
+            tanTouRunState = 'left-m';
+            play('left');
           }
-        } else if (selectData['poleMiddle'] == 1) {
-          if (deviceRunState == 'center-m') {
-            play('center', true);
-            deviceRunState = 'center';
-            tanTouRunState = 'right';
-            play('right', true);
+          //3. 探头右移play('right')
+          if (tanTouRunState == 'left') {
+            tanTouRunState = 'right-m';
+            play('right');
           }
-          if (!deviceRunState) {
-            deviceRunState = 'center';
-            play('center', true);
+        }
+        if (selectData.sensorLeft == 1) {
+          tanTouRunState = 'left';
+          if (!tanTouRunState || tanTouRunState == 'left-m') {
+            play('left', true);
           }
-          if (!tanTouRunState) {
+        }
+        if (selectData.sensorRight == 1) {
+          tanTouRunState = 'right';
+          if (!tanTouRunState || tanTouRunState == 'right-m') {
             play('right', true);
           }
+        }
+      } else if (selectData['poleMiddle'] == 1) {
+        if (deviceRunState == 'center-m') {
+          play('center', true);
+          deviceRunState = 'center';
+          tanTouRunState = 'right';
+          play('right', true);
+        }
+        if (!deviceRunState) {
+          deviceRunState = 'center';
+          play('center', true);
+        }
+        if (!tanTouRunState) {
+          play('right', true);
+        }
 
-          // 横杆在中位
-          if (selectData.sensorLeft == '0' && selectData.sensorMiddle == '0' && selectData.sensorRight == '0') {
-            //5. 探头移到中间play('middle')
-            if (tanTouRunState == 'right') {
-              tanTouRunState = 'middle-m';
-              play('middle');
-            }
-            //6. 探头移到左边play('left')
-            if (tanTouRunState == 'middle') {
-              tanTouRunState = 'left-m';
-              play('left');
-            }
+        // 横杆在中位
+        if (selectData.sensorLeft == '0' && selectData.sensorMiddle == '0' && selectData.sensorRight == '0') {
+          //5. 探头移到中间play('middle')
+          if (tanTouRunState == 'right') {
+            tanTouRunState = 'middle-m';
+            play('middle');
           }
-          if (selectData.sensorMiddle == 1) {
-            tanTouRunState = 'middle';
-            if (!tanTouRunState || tanTouRunState == 'middle-m') {
-              play('middle', true);
-            }
+          //6. 探头移到左边play('left')
+          if (tanTouRunState == 'middle') {
+            tanTouRunState = 'left-m';
+            play('left');
           }
-          if (selectData.sensorLeft == 1) {
-            tanTouRunState = 'left';
-            if (!tanTouRunState || tanTouRunState == 'left-m') {
-              play('left', true);
-            }
+        }
+        if (selectData.sensorMiddle == 1) {
+          tanTouRunState = 'middle';
+          if (!tanTouRunState || tanTouRunState == 'middle-m') {
+            play('middle', true);
           }
-        } else if (selectData['poleNether'] == 1) {
-          if (deviceRunState == 'down-m') {
-            play('down', true);
-            deviceRunState = 'down';
-            tanTouRunState = 'left';
+        }
+        if (selectData.sensorLeft == 1) {
+          tanTouRunState = 'left';
+          if (!tanTouRunState || tanTouRunState == 'left-m') {
             play('left', true);
           }
-          if (!deviceRunState) {
-            play('down', true);
-            deviceRunState = 'down';
+        }
+      } else if (selectData['poleNether'] == 1) {
+        if (deviceRunState == 'down-m') {
+          play('down', true);
+          deviceRunState = 'down';
+          tanTouRunState = 'left';
+          play('left', true);
+        }
+        if (!deviceRunState) {
+          play('down', true);
+          deviceRunState = 'down';
+        }
+        if (!tanTouRunState) {
+          play('left', true);
+        }
+        // 横杆在低位
+        if (selectData.sensorLeft == '0' && selectData.sensorMiddle == '0' && selectData.sensorRight == '0') {
+          //8. 探头移到中间play('middle')
+          if (tanTouRunState == 'left') {
+            tanTouRunState = 'left-middle-m';
+            play('middle');
           }
-          if (!tanTouRunState) {
-            play('left', true);
+          //9. 探头右移play('right')
+          if (tanTouRunState == 'middle1') {
+            tanTouRunState = 'right-m';
+            play('right');
           }
-          // 横杆在低位
-          if (selectData.sensorLeft == '0' && selectData.sensorMiddle == '0' && selectData.sensorRight == '0') {
-            //8. 探头移到中间play('middle')
-            if (tanTouRunState == 'left') {
-              tanTouRunState = 'left-middle-m';
-              play('middle');
-            }
-            //9. 探头右移play('right')
-            if (tanTouRunState == 'middle1') {
-              tanTouRunState = 'right-m';
-              play('right');
-            }
-            // 10. 测风结束,探头移到中间play('middle'),横杆向高位移动
-            if (tanTouRunState == 'right') {
-              tanTouRunState = 'right-middle-m';
-              play('middle');
-            }
+          // 10. 测风结束,探头移到中间play('middle'),横杆向高位移动
+          if (tanTouRunState == 'right') {
+            tanTouRunState = 'right-middle-m';
+            play('middle');
           }
+        }
 
-          if (selectData.sensorMiddle == 1) {
-            if (tanTouRunState == 'left-middle-m') tanTouRunState = 'middle1';
-            if (tanTouRunState == 'right-middle-m') tanTouRunState = 'middle2';
+        if (selectData.sensorMiddle == 1) {
+          if (tanTouRunState == 'left-middle-m') tanTouRunState = 'middle1';
+          if (tanTouRunState == 'right-middle-m') tanTouRunState = 'middle2';
 
-            if (!tanTouRunState || tanTouRunState == 'left-middle-m' || tanTouRunState == 'right-middle-m') {
-              play('middle', true);
-            }
+          if (!tanTouRunState || tanTouRunState == 'left-middle-m' || tanTouRunState == 'right-middle-m') {
+            play('middle', true);
           }
+        }
 
-          if (selectData.sensorRight == 1) {
-            tanTouRunState = 'right';
-            if (!tanTouRunState || tanTouRunState == 'right-m') {
-              play('right', true);
-            }
-          }
-        } else {
-          // 横杆正在运行
-          if (deviceRunState == 'up') {
-            deviceRunState = 'center-m';
-            play('center');
-          }
-          if (deviceRunState == 'center') {
-            deviceRunState = 'down-m';
-            play('down');
-          }
-          if (deviceRunState == 'down') {
-            deviceRunState = 'up-m';
-            play('up');
+        if (selectData.sensorRight == 1) {
+          tanTouRunState = 'right';
+          if (!tanTouRunState || tanTouRunState == 'right-m') {
+            play('right', true);
           }
         }
+      } else {
+        // 横杆正在运行
+        if (deviceRunState == 'up') {
+          deviceRunState = 'center-m';
+          play('center');
+        }
+        if (deviceRunState == 'center') {
+          deviceRunState = 'down-m';
+          play('down');
+        }
+        if (deviceRunState == 'down') {
+          deviceRunState = 'up-m';
+          play('up');
+        }
+      }
 
-        // //正在执行时
-
-        // // 判断上中下是否都为0
-        // if(selectData['poleIncipient'] == 0 && selectData['poleMiddle'] == 0 && selectData['poleNether'] == 0) {
-        //   // 判断是否有前一个状态值,有的话执行
-        //   //没有前一个状态
+      // //正在执行时
 
-        //   //有前一个状态
+      // // 判断上中下是否都为0
+      // if(selectData['poleIncipient'] == 0 && selectData['poleMiddle'] == 0 && selectData['poleNether'] == 0) {
+      //   // 判断是否有前一个状态值,有的话执行
+      //   //没有前一个状态
 
-        //   // 横杆前状态在上位时,横杆中位移动,探头在右边
+      //   //有前一个状态
 
-        //   // 横杆前状态在中位时,横杆下位移动,探头在左边
+      //   // 横杆前状态在上位时,横杆中位移动,探头在右
 
-        //   // 横杆前状态在下位时,横杆上位移动,探头在中间
+      //   // 横杆前状态在中位时,横杆下位移动,探头在左边
 
-        // }else{
-        //   // 判断当前动画停在固定位置
-        //   if(selectData['poleIncipient'] == 1) {
-        //     // 滑杆停在上面,探头在中间
+      //   // 横杆前状态在下位时,横杆上位移动,探头在中间
 
-        //   }else if (selectData['poleMiddle'] == 1) {
-        //     // 滑杆停在中间面,初始探头在右边
+      // }else{
+      //   // 判断当前动画停在固定位置
+      //   if(selectData['poleIncipient'] == 1) {
+      //     // 滑杆停在上面,探头在中间
 
-        //   } else if (selectData['poleNether'] == 1) {
-        //     // 滑杆停在下面,初始探头在左
+      //   }else if (selectData['poleMiddle'] == 1) {
+      //     // 滑杆停在中间面,初始探头在右
 
-        //   }
-        // }
-      } else {
-        // if(selectData['poleIncipient'] == 1){
-        //   deviceRunState = ''
-        //   tanTouRunState = ''
-        // }
-      }
-    }
+      //   } else if (selectData['poleNether'] == 1) {
+      //     // 滑杆停在下面,初始探头在左边
 
-    if (selectData.deviceType == 'windrect_rect') {
-      if (selectData['apparatusRun'] == 1) {
-        const flag = selectData.sign == '0' ? 'center' : selectData.sign == 1 ? 'down' : selectData.sign == 2 ? 'up' : null;
-        if (flag) play(flag);
-      } else {
-        const flag = selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : selectData.sign == '0' ? 'up' : null;
-        if (flag) play(flag, true);
-      }
-    }
-
-    if (selectData.deviceType == 'windrect_ds') {
-      if (selectData['apparatusRun'] == 1 && selectData['sign'] == 2) {
-        if (!deviceRunState) {
-          deviceRunState = 'start';
-          play('down');
-          modelRef.value?.animate?.('down');
-        }
-      } else if (selectData['apparatusRun'] == 0 && selectData['sign'] == 0 && deviceRunState == 'start') {
-        deviceRunState = '';
-        play('up');
-        modelRef.value?.animate?.('up');
-      }
+      //   }
+      // }
+    } else {
+      // if(selectData['poleIncipient'] == 1){
+      //   deviceRunState = ''
+      //   tanTouRunState = ''
+      // }
     }
   }
 
-  // 自测动画方法
-  function testPlay(flag) {
-    if (selectData.deviceType == 'windrect_rect') {
-      setTimeout(() => {
-        play('center');
-      }, 0);
-      setTimeout(() => {
-        play('down');
-      }, 4000);
-      setTimeout(() => {
-        play('up');
-      }, 10000);
-    }
-    if (selectData.deviceType == 'windrect_normal') {
-      setTimeout(() => {
-        play('up');
-      }, 0);
-      setTimeout(() => {
-        play('center');
-      }, 10000);
-      setTimeout(() => {
-        play('down');
-      }, 18000);
-      setTimeout(() => {
-        play('up');
-      }, 21000);
-    }
-    if (selectData.deviceType == 'windrect_ds') {
-      play('moni');
+  if (selectData.deviceType == 'windrect_rect') {
+    if (selectData['apparatusRun'] == 1) {
+      const flag = selectData.sign == '0' ? 'center' : selectData.sign == 1 ? 'down' : selectData.sign == 2 ? 'up' : null;
+      if (flag) play(flag);
+    } else {
+      const flag = selectData.sign == 1 ? 'center' : selectData.sign == 2 ? 'down' : selectData.sign == '0' ? 'up' : null;
+      if (flag) play(flag, true);
     }
   }
 
-  function clearPlay() {
-    modalType.value = 'autoClear';
-    modalIsShow.value = true;
-    if (globalConfig?.simulatedPassword) {
-      controlDevice('', modalType.value);
-    }
-  }
-
-  function startRun() {
-    modalType.value = 'sing';
-    modalIsShow.value = true;
-    if (globalConfig?.simulatedPassword) {
-      controlDevice('', modalType.value);
-    }
-  }
-  // 切换检测数据
-  async function getSelectRow(selectRow, index) {
-    if (selectRow) {
-      loading.value = true;
-      selectRowIndex.value = index;
-      Object.assign(selectData, selectRow);
-      let type = '';
-      if (selectRow['modelType']) {
-        type = selectRow['modelType'];
-        // debugger;
-      } else {
-        if (selectRow.deviceType.startsWith('windrect_rect')) {
-          type = 'lmWindRect';
-        }
-        if (selectRow.deviceType.startsWith('windrect_normal')) {
-          type = 'zdWindRect';
-        }
-        if (selectRow.deviceType.startsWith('windrect_rect_single')) {
-          type = 'lmWindSide';
-        }
-        if (selectRow.deviceType.startsWith('windrect_ds')) {
-          type = 'dsWindRect_move';
-          // type = 'duisheFixed';
-        }
-        if (selectRow.deviceType.startsWith('windrect_ds_four')) {
-          //windrect_ds_two
-          type = 'dsWindRect_four';
-        }
-        if (selectRow.deviceType.startsWith('windrect_ds_two')) {
-          type = 'dsWindRect_two';
-        }
-        if (selectRow.deviceType.startsWith('windrect_ds_sut') || selectRow.deviceType.startsWith('windrect_muti')) {
-          type = 'duisheFixed';
-        }
-        if (
-          selectRow.deviceType.startsWith('windrect_dd') ||
-          selectRow.deviceType == 'windrect_safety' ||
-          selectRow.deviceType == 'windrect_sensor'
-        ) {
-          type = 'ddWindSide';
-        }
+  if (selectData.deviceType == 'windrect_ds') {
+    if (selectData['apparatusRun'] == 1 && selectData['sign'] == 2) {
+      if (!deviceRunState) {
+        deviceRunState = 'start';
+        play('down');
+        modelRef.value?.animate?.('down');
       }
-
-      // const type = selectRowIndex.value >= 1 ? 'lmWindRect' : selectRowIndex.value <= 3 ? 'zdWindRect' : 'dsWindRect';
-      /**
-       * 模型对应的组件,根据实际情况分为二维三维
-       * 这里传入类型type而不是sysOrgCode进行判断展示哪个装置
-       * */
-      if (globalConfig.is2DModel) await setSVGModelType(type);
-      await setModelType(type);
-      loading.value = false;
+    } else if (selectData['apparatusRun'] == 0 && selectData['sign'] == 0 && deviceRunState == 'start') {
       deviceRunState = '';
-      tanTouRunState = '';
-      await getCamera(selectRow.deviceID, playerRef.value);
+      play('up');
+      modelRef.value?.animate?.('up');
     }
   }
-  // 设置模型类型
-  function setSVGModelType(type) {
-    modelComponent.value = getModelComponent(globalConfig.is2DModel, type);
-    return nextTick();
+}
+
+// 自测动画方法
+function testPlay(flag) {
+  if (selectData.deviceType == 'windrect_rect') {
+    setTimeout(() => {
+      play('center');
+    }, 0);
+    setTimeout(() => {
+      play('down');
+    }, 4000);
+    setTimeout(() => {
+      play('up');
+    }, 10000);
   }
-  /* 一键测风 */
-  function handleOk() {
-    modalType.value = 'multiple';
-    modalIsShow.value = true;
-    if (globalConfig?.simulatedPassword) {
-      controlDevice('', modalType.value);
-    }
+  if (selectData.deviceType == 'windrect_normal') {
+    setTimeout(() => {
+      play('up');
+    }, 0);
+    setTimeout(() => {
+      play('center');
+    }, 10000);
+    setTimeout(() => {
+      play('down');
+    }, 18000);
+    setTimeout(() => {
+      play('up');
+    }, 21000);
   }
-
-  /* 打开一键测风弹窗 */
-  function openModel() {
-    setModalProps({ visible: true });
+  if (selectData.deviceType == 'windrect_ds') {
+    play('moni');
   }
+}
 
-  function resetHandle() {
-    modalType.value = 'resetWind';
-    modalIsShow.value = true;
+function clearPlay() {
+  modalType.value = 'autoClear';
+  modalIsShow.value = true;
+  if (globalConfig?.simulatedPassword) {
+    controlDevice('', modalType.value);
   }
+}
 
-  function exportExcel(id) {
-    exportXls({ testid: id });
+function startRun() {
+  modalType.value = 'sing';
+  modalIsShow.value = true;
+  if (globalConfig?.simulatedPassword) {
+    controlDevice('', modalType.value);
   }
+}
+// 切换检测数据
+async function getSelectRow(selectRow, index) {
+  if (selectRow) {
+    loading.value = true;
+    selectRowIndex.value = index;
+    Object.assign(selectData, selectRow);
+    let type = '';
+    if (selectRow['modelType']) {
+      type = selectRow['modelType'];
+      // debugger;
+    } else {
+      if (selectRow.deviceType.startsWith('windrect_rect')) {
+        type = 'lmWindRect';
+      }
+      if (selectRow.deviceType.startsWith('windrect_normal')) {
+        type = 'zdWindRect';
+      }
+      if (selectRow.deviceType.startsWith('windrect_rect_single')) {
+        type = 'lmWindSide';
+      }
+      if (selectRow.deviceType.startsWith('windrect_ds')) {
+        type = 'dsWindRect_move';
+        // type = 'duisheFixed';
+      }
+      if (selectRow.deviceType.startsWith('windrect_ds_four')) {
+        //windrect_ds_two
+        type = 'dsWindRect_four';
+      }
+      if (selectRow.deviceType.startsWith('windrect_ds_two')) {
+        type = 'dsWindRect_two';
+      }
+      if (selectRow.deviceType.startsWith('windrect_ds_sut') || selectRow.deviceType.startsWith('windrect_muti')) {
+        type = 'duisheFixed';
+      }
+      if (selectRow.deviceType.startsWith('windrect_dd') || selectRow.deviceType == 'windrect_safety' || selectRow.deviceType == 'windrect_sensor') {
+        type = 'ddWindSide';
+      }
+    }
 
-  /* 关闭一键测风弹窗 */
-  function handleCancel() {
-    setModalProps({ visible: false });
-    modalTable.value.clearSelectedRowKeys();
+    // const type = selectRowIndex.value >= 1 ? 'lmWindRect' : selectRowIndex.value <= 3 ? 'zdWindRect' : 'dsWindRect';
+    /**
+     * 模型对应的组件,根据实际情况分为二维三维
+     * 这里传入类型type而不是sysOrgCode进行判断展示哪个装置
+     * */
+    if (globalConfig.is2DModel) await setSVGModelType(type);
+    await setModelType(type);
+    loading.value = false;
+    deviceRunState = '';
+    tanTouRunState = '';
+    await getCamera(selectRow.deviceID, playerRef.value);
   }
-
-  /* 关闭一键测风控制*/
-  function handleCancelControl() {
-    modalIsShow.value = false;
+}
+// 设置模型类型
+function setSVGModelType(type) {
+  modelComponent.value = getModelComponent(globalConfig.is2DModel, type);
+  return nextTick();
+}
+/* 一键测风 */
+function handleOk() {
+  modalType.value = 'multiple';
+  modalIsShow.value = true;
+  if (globalConfig?.simulatedPassword) {
+    controlDevice('', modalType.value);
   }
-
-  function controlDevice(passWord, type) {
-    try {
-      if (type == 'sing') {
-        testWind({
-          ids: [selectData.deviceID],
-          maxnum: 1000,
-          windnum: 1,
-          password: passWord || globalConfig?.simulatedPassword,
-        }).then((res) => {
-          if (res && res.success === false) {
-            message.error(res.message);
+}
+
+/* 打开一键测风弹窗 */
+function openModel() {
+  setModalProps({ visible: true });
+}
+
+function resetHandle() {
+  modalType.value = 'resetWind';
+  modalIsShow.value = true;
+}
+
+function exportExcel(id) {
+  exportXls({ testid: id });
+}
+
+/* 关闭一键测风弹窗 */
+function handleCancel() {
+  setModalProps({ visible: false });
+  modalTable.value.clearSelectedRowKeys();
+}
+
+/* 关闭一键测风控制*/
+function handleCancelControl() {
+  modalIsShow.value = false;
+}
+
+function controlDevice(passWord, type) {
+  try {
+    if (type == 'sing') {
+      testWind({
+        ids: [selectData.deviceID],
+        maxnum: 1000,
+        windnum: 1,
+        password: passWord || globalConfig?.simulatedPassword,
+      }).then((res) => {
+        if (res && res.success === false) {
+          message.error(res.message);
+        } else {
+          if (globalConfig.History_Type == 'remote') {
+            message.success('指令已下发至生产管控平台成功!');
           } else {
-            if (globalConfig.History_Type == 'remote') {
-              message.success('指令已下发至生产管控平台成功!');
-            } else {
-              message.success('指令已下发成功!');
-            }
+            message.success('指令已下发成功!');
           }
-          modalIsShow.value = false;
-        });
-      } else if (type == 'multiple') {
-        const ids = toRaw(modalTable.value.selectedRowKeys);
-        testWind({
-          ids: ids,
-          maxnum: 1000,
-          windnum: modalTable.value.selectedRowKeys.length,
-          password: passWord || globalConfig?.simulatedPassword,
-        }).then((res) => {
-          if (res && res.success === false) {
-            message.error(res.message);
+        }
+        modalIsShow.value = false;
+      });
+    } else if (type == 'multiple') {
+      const ids = toRaw(modalTable.value.selectedRowKeys);
+      testWind({
+        ids: ids,
+        maxnum: 1000,
+        windnum: modalTable.value.selectedRowKeys.length,
+        password: passWord || globalConfig?.simulatedPassword,
+      }).then((res) => {
+        if (res && res.success === false) {
+          message.error(res.message);
+        } else {
+          if (globalConfig.History_Type == 'remote') {
+            message.success('指令已下发至生产管控平台成功!');
           } else {
-            if (globalConfig.History_Type == 'remote') {
-              message.success('指令已下发至生产管控平台成功!');
-            } else {
-              message.success('指令已下发成功!');
-            }
+            message.success('指令已下发成功!');
           }
-          modalIsShow.value = false;
-          setModalProps({ visible: false });
-          modalTable.value.clearSelectedRowKeys();
-        });
-      } else if (type == 'autoClear') {
-        const data = {
-          deviceid: selectData.deviceID,
-          devicetype: selectData.deviceType,
-          paramcode: 'autoClear',
-          value: null,
-          password: passWord || globalConfig?.simulatedPassword,
-          masterComputer: selectData.masterComputer,
-        };
-        deviceControlApi(data).then((res) => {
-          // 模拟时开启
-          if (res.success) {
-            if (globalConfig.History_Type == 'remote') {
-              message.success('指令已下发至生产管控平台成功!');
-            } else {
-              message.success('指令已下发成功!');
-            }
+        }
+        modalIsShow.value = false;
+        setModalProps({ visible: false });
+        modalTable.value.clearSelectedRowKeys();
+      });
+    } else if (type == 'autoClear') {
+      const data = {
+        deviceid: selectData.deviceID,
+        devicetype: selectData.deviceType,
+        paramcode: 'autoClear',
+        value: null,
+        password: passWord || globalConfig?.simulatedPassword,
+        masterComputer: selectData.masterComputer,
+      };
+      deviceControlApi(data).then((res) => {
+        // 模拟时开启
+        if (res.success) {
+          if (globalConfig.History_Type == 'remote') {
+            message.success('指令已下发至生产管控平台成功!');
           } else {
-            message.error(res.message);
+            message.success('指令已下发成功!');
           }
-          modalIsShow.value = false;
-        });
-      } else if (type == 'resetWind') {
-        resetWind({}).then((res: any) => {
-          message.info(res);
-        });
+        } else {
+          message.error(res.message);
+        }
         modalIsShow.value = false;
-      }
-    } catch (error) {
-      message.error('测风失败,请联系管理员。。。');
+      });
+    } else if (type == 'resetWind') {
+      resetWind({}).then((res: any) => {
+        message.info(res);
+      });
       modalIsShow.value = false;
     }
+  } catch (error) {
+    message.error('测风失败,请联系管理员。。。');
+    modalIsShow.value = false;
   }
+}
 
-  /** 避灾路线上的测风装置 */
-  async function getPathList() {
-    const pathArr = await pathList({});
-    criticalPathList.value = pathArr.records.filter((item) => {
-      return item.strsystype == 3;
-    });
-  }
-
-  /* 根据路线选择测风装置 */
-  function selectCriticalPath(pathId) {
-    deviceList({ deviceType: 'wind', sysId: pathId }).then((res) => {
-      const ids: string[] = [];
-      res.records.forEach((item) => {
-        ids.push(item.id);
-      });
-      if (modalTable.value) modalTable.value.setSelectedRowKeys(ids);
-    });
-  }
-
-  function deviceEdit(e: Event, type: string, record) {
-    e.stopPropagation();
-    openModal(true, {
-      type,
-      deviceId: record['deviceID'],
-    });
-  }
-
-  onBeforeMount(() => {
-    getPathList();
+/** 避灾路线上的测风装置 */
+async function getPathList() {
+  const pathArr = await pathList({});
+  criticalPathList.value = pathArr.records.filter((item) => {
+    return item.strsystype == 3;
   });
-
-  onMounted(async () => {
-    // const playerDom = document.getElementById('cf-player1')?.getElementsByClassName('vjs-tech')[0];
-    // loading.value = true;
-    // mountedThree(playerDom).then(async () => {
-    //   getMonitor(true);
-    //   // loading.value = false;
-    // });
-    const { query } = unref(currentRoute);
-    if (query['deviceType']) deviceType.value = query['deviceType'] as string;
-    loading.value = true;
-    mountedThree(null).then(async () => {
-      await getMonitor(true);
-      loading.value = false;
+}
+
+/* 根据路线选择测风装置 */
+function selectCriticalPath(pathId) {
+  deviceList({ deviceType: 'wind', sysId: pathId }).then((res) => {
+    const ids: string[] = [];
+    res.records.forEach((item) => {
+      ids.push(item.id);
     });
+    if (modalTable.value) modalTable.value.setSelectedRowKeys(ids);
   });
+}
 
-  onUnmounted(() => {
-    removeCamera();
-    if (timer) {
-      clearTimeout(timer);
-      timer = undefined;
-    }
-    destroy();
+function deviceEdit(e: Event, type: string, record) {
+  e.stopPropagation();
+  openModal(true, {
+    type,
+    deviceId: record['deviceID'],
   });
-</script>
-<style scoped lang="less">
-  @import '/@/design/theme.less';
-  @import '/@/design/vent/modal.less';
-  @ventSpace: zxm;
+}
+
+onBeforeMount(() => {
+  getPathList();
+});
+
+onMounted(async () => {
+  // const playerDom = document.getElementById('cf-player1')?.getElementsByClassName('vjs-tech')[0];
+  // loading.value = true;
+  // mountedThree(playerDom).then(async () => {
+  //   getMonitor(true);
+  //   // loading.value = false;
+  // });
+  const { query } = unref(currentRoute);
+  if (query['deviceType']) deviceType.value = query['deviceType'] as string;
+  loading.value = true;
+  mountedThree(null).then(async () => {
+    await getMonitor(true);
+    loading.value = false;
+  });
+});
 
-  :deep(.@{ventSpace}-tabs-tabpane-active) {
-    height: 100%;
+onUnmounted(() => {
+  removeCamera();
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
   }
-  .scene-box {
-    .bottom-tabs-box {
-      height: 350px;
-    }
+  destroy();
+});
+</script>
+<style scoped lang="less">
+@import '/@/design/theme.less';
+@import '/@/design/vent/modal.less';
+@ventSpace: zxm;
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  height: 100%;
+}
+.scene-box {
+  .bottom-tabs-box {
+    height: 350px;
   }
-  .head-line {
+}
+.head-line {
+  display: flex;
+  flex-direction: row;
+  justify-content: space-between;
+  .button-box {
+    position: relative;
+    padding: 5px;
+    border: 1px transparent solid;
+    border-radius: 5px;
+    margin-left: 8px;
+    margin-right: 8px;
+    width: auto;
+    height: 34px;
+    border: 1px solid var(--vent-base-border);
     display: flex;
-    flex-direction: row;
-    justify-content: space-between;
-    .button-box {
-      position: relative;
-      padding: 5px;
-      border: 1px transparent solid;
-      border-radius: 5px;
-      margin-left: 8px;
-      margin-right: 8px;
-      width: auto;
-      height: 34px;
-      border: 1px solid var(--vent-base-border);
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      color: var(--vent-font-color);
-      padding: 0 15px;
-      cursor: pointer;
-      pointer-events: auto;
-      &:hover {
-        background: var(--vent-device-manager-control-btn-hover);
-      }
-      &::before {
-        width: calc(100% - 6px);
-        height: 26px;
-        content: '';
-        position: absolute;
-        top: 3px;
-        right: 0;
-        left: 3px;
-        bottom: 0;
-        z-index: -1;
-        border-radius: inherit; /*important*/
-        background: var(--vent-device-manager-control-btn);
-      }
+    align-items: center;
+    justify-content: center;
+    color: var(--vent-font-color);
+    padding: 0 15px;
+    cursor: pointer;
+    pointer-events: auto;
+    &:hover {
+      background: var(--vent-device-manager-control-btn-hover);
+    }
+    &::before {
+      width: calc(100% - 6px);
+      height: 26px;
+      content: '';
+      position: absolute;
+      top: 3px;
+      right: 0;
+      left: 3px;
+      bottom: 0;
+      z-index: -1;
+      border-radius: inherit; /*important*/
+      background: var(--vent-device-manager-control-btn);
     }
   }
-  :deep(.@{ventSpace}-picker-datetime-panel) {
-    height: 200px !important;
-    overflow-y: auto !important;
-  }
+}
+:deep(.@{ventSpace}-picker-datetime-panel) {
+  height: 200px !important;
+  overflow-y: auto !important;
+}
 </style>

+ 9 - 0
src/views/vent/sys/setting/index.vue

@@ -57,6 +57,15 @@
   });
 </script>
 <style lang="less" scoped>
+  @import '/@/design/theme.less';
+  // 绿色主题特化的变量
+  @{theme-green} {
+    .setting-box {
+      border: 1px solid #3c5c64;
+      box-shadow: 0 0 20px #44b4ff33 inset;
+      background-color: #ffffff11;
+    }
+  }
   .setting-box {
     margin: 10px 8px;
     height: calc(100% - 72px);

+ 4 - 0
src/views/vent/sys/setting/setting.data.ts

@@ -95,6 +95,10 @@ export const formSchema: FormSchema[] = [
           label: '深蓝(开发中)',
           value: ThemeEnum.DEEPBLUE,
         },
+        {
+          label: '绿色(开发中)',
+          value: ThemeEnum.GREEN,
+        },
       ],
     },
   },

部分文件因文件數量過多而無法顯示