Pārlūkot izejas kodu

Merge branch 'master' of http://47.94.222.6:3003/lizuo/VentSystem_2.0_front

lxh 1 gadu atpakaļ
vecāks
revīzija
42a0d9d05b
78 mainītis faili ar 3093 papildinājumiem un 995 dzēšanām
  1. 1 3
      .env
  2. 4 3
      .env.development
  3. 15 5
      .env.production
  4. 2 0
      .env.test
  5. 3 3
      Dockerfile
  6. 2 2
      package.json
  7. 8 8
      pnpm-lock.yaml
  8. BIN
      public/model/glft/fire/chamber.glb
  9. BIN
      public/model/glft/fm/Fm-wall.glb
  10. BIN
      public/model/glft/fm/Fm-wire.glb
  11. BIN
      public/model/hdr/123.hdr
  12. 6 0
      src/App.vue
  13. BIN
      src/assets/font/DS-DIGIT.TTF
  14. BIN
      src/assets/font/yjsz.TTF
  15. 6 0
      src/assets/icons/aveg-temperature.svg
  16. 6 0
      src/assets/icons/max-temperature.svg.svg
  17. 6 0
      src/assets/icons/min-temperature.svg
  18. 3 0
      src/assets/icons/risk-level.svg
  19. BIN
      src/assets/images/vent/home/modal-top.png
  20. BIN
      src/assets/images/vent/model_image/border_bg01.png
  21. BIN
      src/assets/images/vent/model_image/dust-bg.png
  22. 2 3
      src/components/Form/src/jeecg/components/MTreeSelect.vue
  23. 7 6
      src/components/chart/BarAndLine.vue
  24. 97 0
      src/components/chart/BarAndLineCustom.vue
  25. 4 0
      src/design/vent/antCss.less
  26. 9 2
      src/design/vent/index.less
  27. 6 4
      src/design/vent/modal.less
  28. 3 2
      src/enums/pageEnum.ts
  29. 0 9
      src/layouts/default/content/index.vue
  30. 5 0
      src/layouts/default/header/index.vue
  31. 0 43
      src/router/routes/basic.ts
  32. 8 5
      src/utils/echartsUtil.ts
  33. 2 2
      src/utils/threejs/main.worker.ts
  34. 3 4
      src/utils/threejs/util.ts
  35. 1 1
      src/views/demo/comp/modal/Modal2.vue
  36. 74 0
      src/views/vent/comment/components/fourBorderBg.vue
  37. 0 55
      src/views/vent/deviceManager/comment/NormalTable.vue
  38. 0 56
      src/views/vent/deviceManager/comment/normalBtnTable.vue
  39. 0 2
      src/views/vent/deviceManager/equipManager/equip.data.ts
  40. 1 25
      src/views/vent/deviceManager/pointTabel/point.data.ts
  41. 9 0
      src/views/vent/deviceManager/workingFace/workingFace.data.ts
  42. 18 0
      src/views/vent/monitorManager/chamberMonitor/chamber.api.ts
  43. 0 0
      src/views/vent/monitorManager/chamberMonitor/chamber.data.ts
  44. 107 0
      src/views/vent/monitorManager/chamberMonitor/chamber.threejs.base.ts
  45. 115 0
      src/views/vent/monitorManager/chamberMonitor/chamber.threejs.ts
  46. 212 0
      src/views/vent/monitorManager/chamberMonitor/index.vue
  47. 8 0
      src/views/vent/monitorManager/comment/AlarmHistoryTable.vue
  48. 2 3
      src/views/vent/monitorManager/comment/DeviceEcharts.vue
  49. 16 4
      src/views/vent/monitorManager/comment/HandlerHistoryTable.vue
  50. 9 1
      src/views/vent/monitorManager/comment/HistoryTable.vue
  51. 6 11
      src/views/vent/monitorManager/comment/MonitorTable.vue
  52. 20 0
      src/views/vent/monitorManager/deviceMonitor/device.api.ts
  53. 5 0
      src/views/vent/monitorManager/deviceMonitor/device.data.ts
  54. 271 0
      src/views/vent/monitorManager/deviceMonitor/index.vue
  55. 380 0
      src/views/vent/monitorManager/deviceMonitor/modal/dust.modal.vue
  56. 416 0
      src/views/vent/monitorManager/deviceMonitor/modal/fiber.modal.vue
  57. 5 7
      src/views/vent/monitorManager/fanLocalMonitor/index.vue
  58. 0 15
      src/views/vent/monitorManager/fiberMonitor/fiber.belt.threejs.ts
  59. 15 27
      src/views/vent/monitorManager/fiberMonitor/fiber.data.ts
  60. 3 3
      src/views/vent/monitorManager/fiberMonitor/fiber.workFace.threejs.ts
  61. 16 12
      src/views/vent/monitorManager/fiberMonitor/index.vue
  62. 1 1
      src/views/vent/monitorManager/gateMonitor/gate.api.ts
  63. 3 3
      src/views/vent/monitorManager/gateMonitor/index.vue
  64. 6 8
      src/views/vent/monitorManager/mainFanMonitor/index.vue
  65. 87 0
      src/views/vent/monitorManager/nitrogen/components/bottomMenu.vue
  66. 17 0
      src/views/vent/monitorManager/nitrogen/components/nitrogenAlarmHistory.vue
  67. 246 0
      src/views/vent/monitorManager/nitrogen/components/nitrogenEcharts.vue
  68. 16 0
      src/views/vent/monitorManager/nitrogen/components/nitrogenHandleHistory.vue
  69. 16 0
      src/views/vent/monitorManager/nitrogen/components/nitrogenHistory.vue
  70. 615 0
      src/views/vent/monitorManager/nitrogen/components/nitrogenHome.vue
  71. 57 406
      src/views/vent/monitorManager/nitrogen/index.vue
  72. 17 0
      src/views/vent/monitorManager/nitrogen/nitrogen.api.ts
  73. 15 10
      src/views/vent/monitorManager/nitrogen/nitrogen.data.ts
  74. 67 231
      src/views/vent/monitorManager/nitrogen/nitrogen.dishang.threejs.ts
  75. 11 7
      src/views/vent/monitorManager/nitrogen/nitrogen.threejs.ts
  76. 1 1
      src/views/vent/monitorManager/sensorMonitor/index.vue
  77. 1 1
      src/views/vent/monitorManager/windowMonitor/index.vue
  78. 0 1
      src/views/vent/monitorManager/windowMonitor/window.api.ts

+ 1 - 3
.env

@@ -2,7 +2,7 @@
 VITE_PORT = 3100
 
 #  网站标题
-VITE_GLOB_APP_TITLE = XXX智能管控系统
+VITE_GLOB_APP_TITLE = 智能通风管控系统
 
 # 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
 VITE_GLOB_APP_SHORT_NAME = JeecgBootAdmin
@@ -18,5 +18,3 @@ VITE_GLOB_APP_OPEN_QIANKUN=true
 
 # 文件预览地址
 VITE_GLOB_ONLINE_VIEW_URL=http://fileview.jeecg.com/onlinePreview
-
-

+ 4 - 3
.env.development

@@ -7,7 +7,7 @@ VITE_PUBLIC_PATH = /
 # 跨域代理,您可以配置多个 ,请注意,没有换行符
 #VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
 VITE_PROXY = [["/jeecgsystem","http://47.94.222.6:9999"],["/upload","http://localhost:3300/upload"]]
-#VITE_PROXY = [["/jeecgsystem","http://192.168.1.88:9999"],["/upload","http://192.168.1.88/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://192.168.1.4:9999"],["/upload","http://localhost:3300/upload"]]
 
 # 控制台不输出
 VITE_DROP_CONSOLE = false
@@ -16,14 +16,15 @@ VITE_DROP_CONSOLE = false
 #VITE_GLOB_API_URL=/jeecgboot
 VITE_GLOB_API_URL=/jeecgsystem
 
+
 #后台接口全路径地址(必填)
-#VITE_GLOB_DOMAIN_URL=http://192.168.1.88:9999
 VITE_GLOB_DOMAIN_URL=http://47.94.222.6:9999
+#VITE_GLOB_DOMAIN_URL=http://192.168.1.4:9999
 
 # 接口前缀
 VITE_GLOB_API_URL_PREFIX=
 
 #微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
 #VITE_APP_SUB_APP = [["micro-need-air", "//182.92.126.35:8099/"], ["micro-vent-3dModal", "//localhost:8091/"], ["micro-fire-front", "//localhost:8090/"]]
-VITE_APP_SUB_APP = [["micro-vent-3dModal", "//localhost:8091/"], ["micro-need-air", "//localhost:8099/"]]
+VITE_APP_SUB_APP = [["micro-vent-3dModal", "//localhost:8091/"], ["micro-need-air", "//localhost:8099/"], ["micro-fire-front", "//localhost:8090/"]]
 

+ 15 - 5
.env.production

@@ -14,15 +14,23 @@ VITE_BUILD_COMPRESS = 'gzip'
 
 # 使用压缩时是否删除原始文件,默认为false
 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
-
-VITE_PROXY = [["/jeecgsystem","http://47.94.222.6:9999"],["/upload","http://localhost:3300/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://47.94.222.6:9999"],["/upload","http://localhost:3300/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://192.168.0.79:9999"],["/upload","http://localhost:3300/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://42.194.132.36:8099"],["/upload","http://localhost:3300/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://192.168.0.30:8086"],["/upload","http://localhost:3300/upload"]]
+VITE_PROXY = [["/jeecgsystem","http://127.0.0.1:9999"],["/upload","http://localhost:3300/upload"]]
 
 #后台接口父地址(必填)
 VITE_GLOB_API_URL=/jeecgsystem
 
 #后台接口全路径地址(必填)
 #VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot
-VITE_GLOB_DOMAIN_URL=http://47.94.222.6:9999
+#VITE_GLOB_DOMAIN_URL=http://47.94.222.6:9999
+VITE_GLOB_DOMAIN_URL=http://127.0.0.1:9999
+#VITE_GLOB_DOMAIN_URL=http://42.194.132.36:8099
+#采育服务器
+#VITE_GLOB_DOMAIN_URL=http://192.168.0.79:9999
+#VITE_GLOB_DOMAIN_URL=http://192.168.0.30:8086
 
 # 接口父路径前缀
 VITE_GLOB_API_URL_PREFIX=
@@ -37,5 +45,7 @@ VITE_USE_PWA = false
 VITE_LEGACY = false
 
 #微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
-#VITE_APP_SUB_APP = [["micro-need-air", "//182.92.126.35:8099/"], ["micro-vent-3dModal", "//47.94.222.6:7121/"]]
-VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:20000/"], ["micro-vent-3dModal", "//127.0.0.1:30000/"]]
+#VITE_APP_SUB_APP = [["micro-need-air", "//47.94.222.6:7123/"], ["micro-vent-3dModal", "//47.94.222.6:7121/"],["micro-fire-front", "//47.94.222.6:7124/"]]
+#VITE_APP_SUB_APP = []
+#VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:20000/"], ["micro-vent-3dModal", "//127.0.0.1:30000/"], ["micro-fire-front", "//127.0.0.1:40000/"]]
+VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:7123/"], ["micro-vent-3dModal", "//127.0.0.1:7121/"]]

+ 2 - 0
.env.test

@@ -32,3 +32,5 @@ VITE_USE_PWA = false
 
 # 是否兼容旧浏览器
 VITE_LEGACY = false
+
+VITE_GLOB_IS_SIMULATE=true

+ 3 - 3
Dockerfile

@@ -4,8 +4,8 @@ VOLUME /tmp
 ENV LANG en_US.UTF-8
 RUN echo "server {  \
                       listen       80; \
-                      location   /jeecgboot { \
-                      proxy_pass              http://jeecg-boot-system:8080/jeecg-boot; \
+                      location   /jeecgboot/ { \
+                      proxy_pass              http://jeecg-boot-system:8080/jeecg-boot/; \
                       proxy_redirect          off; \
                       proxy_set_header        Host jeecg-boot-system; \
                       proxy_set_header        X-Real-IP \$remote_addr; \
@@ -27,4 +27,4 @@ RUN echo "server {  \
 
 ADD dist/ /var/www/html/
 EXPOSE 80
-EXPOSE 443
+EXPOSE 443

+ 2 - 2
package.json

@@ -48,7 +48,7 @@
     "@vueuse/core": "^8.3.0",
     "@vueuse/shared": "^8.3.0",
     "@zxcvbn-ts/core": "^2.0.1",
-    "ant-design-vue": "^3.2.14",
+    "ant-design-vue": "^3.2.19",
     "axios": "^0.26.1",
     "china-area-data": "^5.0.1",
     "clipboard": "^2.0.8",
@@ -80,7 +80,7 @@
     "resize-observer-polyfill": "^1.5.1",
     "showdown": "^2.1.0",
     "sortablejs": "^1.15.0",
-    "three": "^0.149.0",
+    "three": "^0.150.1",
     "tinymce": "^5.10.3",
     "vditor": "^3.8.13",
     "vite-plugin-theme": "^0.8.6",

+ 8 - 8
pnpm-lock.yaml

@@ -45,7 +45,7 @@ specifiers:
   '@vueuse/core': ^8.3.0
   '@vueuse/shared': ^8.3.0
   '@zxcvbn-ts/core': ^2.0.1
-  ant-design-vue: ^3.2.14
+  ant-design-vue: ^3.2.19
   autoprefixer: ^10.4.4
   axios: ^0.26.1
   china-area-data: ^5.0.1
@@ -116,7 +116,7 @@ specifiers:
   stylelint-config-recommended-vue: ^1.4.0
   stylelint-config-standard: ^25.0.0
   stylelint-order: ^5.0.0
-  three: ^0.149.0
+  three: ^0.150.1
   tinymce: ^5.10.3
   ts-jest: ^27.0.7
   ts-node: ^10.7.0
@@ -169,7 +169,7 @@ dependencies:
   '@vueuse/core': 8.9.4_vue@3.2.45
   '@vueuse/shared': 8.9.4_vue@3.2.45
   '@zxcvbn-ts/core': 2.1.0
-  ant-design-vue: 3.2.15_vue@3.2.45
+  ant-design-vue: 3.2.19_vue@3.2.45
   axios: 0.26.1
   china-area-data: 5.0.1
   clipboard: 2.0.11
@@ -201,7 +201,7 @@ dependencies:
   resize-observer-polyfill: 1.5.1
   showdown: 2.1.0
   sortablejs: 1.15.0
-  three: 0.149.0
+  three: 0.150.1
   tinymce: 5.10.7
   vditor: 3.8.18
   vite-plugin-theme: 0.8.6_vite@3.2.5
@@ -3620,8 +3620,8 @@ packages:
     engines: {node: '>=12'}
     dev: true
 
-  /ant-design-vue/3.2.15_vue@3.2.45:
-    resolution: {integrity: sha512-sJfE7LWimSdAPe4dzNyQBrmVMnOTNQTkG9oOyr+7W8qIYrX8sYWyC68Nn1uum4KBJUSZUa/BU6dohvTG0urBhA==}
+  /ant-design-vue/3.2.19_vue@3.2.45:
+    resolution: {integrity: sha512-weizTa70qNhyj8tOoplTcpt85OkVHpnreK2skdTmORFAGDGvF15zyoqCNg2tByzn2xxf2DloQQvZYKlN/i0CGw==}
     engines: {node: '>=12.22.0'}
     peerDependencies:
       vue: '>=3.2.0'
@@ -11767,8 +11767,8 @@ packages:
     resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
     dev: true
 
-  /three/0.149.0:
-    resolution: {integrity: sha512-tohpUxPDht0qExRLDTM8sjRLc5d9STURNrdnK3w9A+V4pxaTBfKWWT/IqtiLfg23Vfc3Z+ImNfvRw1/0CtxrkQ==, tarball: three/-/three-0.149.0.tgz}
+  /three/0.150.1:
+    resolution: {integrity: sha512-5C1MqKUWaHYo13BX0Q64qcdwImgnnjSOFgBscOzAo8MYCzEtqfQqorEKMcajnA3FHy1yVlIe9AmaMQ0OQracNA==}
     dev: false
 
   /throat/6.0.1:

BIN
public/model/glft/fire/chamber.glb


BIN
public/model/glft/fm/Fm-wall.glb


BIN
public/model/glft/fm/Fm-wire.glb


BIN
public/model/hdr/123.hdr


+ 6 - 0
src/App.vue

@@ -48,4 +48,10 @@
     font-weight: normal;
     font-style: normal;
   }
+  @font-face {
+    font-family: 'electronicFont';
+    src: url('/@/assets/font/DS-DIGIT.TTF');
+    font-weight: normal;
+    font-style: normal;
+  }
 </style>

BIN
src/assets/font/DS-DIGIT.TTF


BIN
src/assets/font/yjsz.TTF


+ 6 - 0
src/assets/icons/aveg-temperature.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="50.313" height="73.149" viewBox="0 0 50.313 73.149">
+  <g id="组_13141" data-name="组 13141" transform="translate(-506.549 -355.112)">
+    <path id="路径_55369" data-name="路径 55369" d="M234.565,40.948V23.1a1.971,1.971,0,0,0-1.968-1.968h-.156a1.909,1.909,0,0,0-1.91,1.91v17.9a6.93,6.93,0,0,0-5.086,6.606,7.106,7.106,0,1,0,9.12-6.606Zm10.451-7.905a1.8,1.8,0,0,1-.7-1.364V11.5a11.773,11.773,0,0,0-23.54,0v19.6a2.8,2.8,0,0,1-.955,2.15,18.709,18.709,0,0,0-6.69,14.3,19.427,19.427,0,0,0,38.844,0A18.71,18.71,0,0,0,245.016,33.043ZM232.545,60.5a13.14,13.14,0,0,1-13.3-12.946,12.824,12.824,0,0,1,6.216-10.939l.942-.578a1.044,1.044,0,0,0,.494-.883V11.5a5.66,5.66,0,0,1,11.315,0v23.65a1.044,1.044,0,0,0,.494.883l.942.578a12.81,12.81,0,0,1,6.21,10.939A13.154,13.154,0,0,1,232.545,60.5Z" transform="translate(293.42 361.739)" fill="#fff"/>
+    <path id="路径_55371" data-name="路径 55371" d="M64,120.4v3.586H81.725V120.4Zm0,21.934H81.725v-3.586H64Zm0-9.172H81.725v-3.586H64Z" transform="translate(475.138 234.712)" fill="#fff"/>
+  </g>
+</svg>

+ 6 - 0
src/assets/icons/max-temperature.svg.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="50.313" height="73.149" viewBox="0 0 50.313 73.149">
+  <g id="组_13139" data-name="组 13139" transform="translate(-506.549 -355.112)">
+    <path id="路径_55369" data-name="路径 55369" d="M234.565,40.948V23.1a1.971,1.971,0,0,0-1.968-1.968h-.156a1.909,1.909,0,0,0-1.91,1.91v17.9a6.93,6.93,0,0,0-5.086,6.606,7.106,7.106,0,1,0,9.12-6.606Zm10.451-7.905a1.8,1.8,0,0,1-.7-1.364V11.5a11.773,11.773,0,0,0-23.54,0v19.6a2.8,2.8,0,0,1-.955,2.15,18.709,18.709,0,0,0-6.69,14.3,19.427,19.427,0,0,0,38.844,0A18.71,18.71,0,0,0,245.016,33.043ZM232.545,60.5a13.14,13.14,0,0,1-13.3-12.946,12.824,12.824,0,0,1,6.216-10.939l.942-.578a1.044,1.044,0,0,0,.494-.883V11.5a5.66,5.66,0,0,1,11.315,0v23.65a1.044,1.044,0,0,0,.494.883l.942.578a12.81,12.81,0,0,1,6.21,10.939A13.154,13.154,0,0,1,232.545,60.5Z" transform="translate(293.42 361.739)" fill="#fff"/>
+    <path id="路径_55370" data-name="路径 55370" d="M284.718,159.821v14.623h2.954V159.821l3.1,3.1,2.068-2.216L286.2,154.06l-6.647,6.647,2.068,2.068Zm-7.385-7.533h17.725v-2.954H277.333Z" transform="translate(261.805 205.778)" fill="#fff"/>
+  </g>
+</svg>

+ 6 - 0
src/assets/icons/min-temperature.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="50.313" height="73.149" viewBox="0 0 50.313 73.149">
+  <g id="组_13140" data-name="组 13140" transform="translate(-506.549 -355.112)">
+    <path id="路径_55369" data-name="路径 55369" d="M234.565,40.948V23.1a1.971,1.971,0,0,0-1.968-1.968h-.156a1.909,1.909,0,0,0-1.91,1.91v17.9a6.93,6.93,0,0,0-5.086,6.606,7.106,7.106,0,1,0,9.12-6.606Zm10.451-7.905a1.8,1.8,0,0,1-.7-1.364V11.5a11.773,11.773,0,0,0-23.54,0v19.6a2.8,2.8,0,0,1-.955,2.15,18.709,18.709,0,0,0-6.69,14.3,19.427,19.427,0,0,0,38.844,0A18.71,18.71,0,0,0,245.016,33.043ZM232.545,60.5a13.14,13.14,0,0,1-13.3-12.946,12.824,12.824,0,0,1,6.216-10.939l.942-.578a1.044,1.044,0,0,0,.494-.883V11.5a5.66,5.66,0,0,1,11.315,0v23.65a1.044,1.044,0,0,0,.494.883l.942.578a12.81,12.81,0,0,1,6.21,10.939A13.154,13.154,0,0,1,232.545,60.5Z" transform="translate(293.42 361.739)" fill="#fff"/>
+    <path id="路径_55370" data-name="路径 55370" d="M284.718,163.956V149.334h2.954v14.623l3.1-3.1,2.068,2.216-6.647,6.647-6.647-6.647L281.616,161Zm-7.385,7.533h17.725v2.954H277.333Z" transform="translate(261.805 205.778)" fill="#fff"/>
+  </g>
+</svg>

+ 3 - 0
src/assets/icons/risk-level.svg

@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="67.183" height="67.183" viewBox="0 0 67.183 67.183">
+  <path id="路径_55372" data-name="路径 55372" d="M53.746,60.465H13.437a3.359,3.359,0,0,0,0,6.718h40.31a3.359,3.359,0,1,0,0-6.718ZM16.8,57.106H50.387V33.592a16.8,16.8,0,1,0-33.592,0Zm16.8-43.669a3.359,3.359,0,0,0,3.359-3.359V3.359a3.359,3.359,0,0,0-6.718,0v6.718A3.359,3.359,0,0,0,33.592,13.437ZM14.579,19.349a3.373,3.373,0,0,0,4.77-4.77l-4.77-4.736a3.359,3.359,0,0,0-4.736,4.736ZM13.437,33.592a3.359,3.359,0,0,0-3.359-3.359H3.359a3.359,3.359,0,0,0,0,6.718h6.718A3.359,3.359,0,0,0,13.437,33.592Zm50.387-3.359H57.106a3.359,3.359,0,0,0,0,6.718h6.718a3.359,3.359,0,0,0,0-6.718ZM52.6,19.349l4.736-4.736A3.359,3.359,0,0,0,52.6,9.876l-4.77,4.7a3.359,3.359,0,0,0,4.736,4.736Z" fill="#fff"/>
+</svg>

BIN
src/assets/images/vent/home/modal-top.png


BIN
src/assets/images/vent/model_image/border_bg01.png


BIN
src/assets/images/vent/model_image/dust-bg.png


+ 2 - 3
src/components/Form/src/jeecg/components/MTreeSelect.vue

@@ -2,6 +2,7 @@
   <a-tree-select
     allowClear
     style="width: 100%"
+    :showSearch = "false"
     :getPopupContainer="(node) => node.parentNode"
     :dropdownStyle="{ maxHeight: '400px', overflow: 'auto', zIndex: 99999 }"
     :placeholder="placeholder"
@@ -20,12 +21,10 @@
    * 异步树加载组件 通过传入表名 显示字段 存储字段 加载一个树控件
    * <j-tree-select dict="aa_tree_test,aad,id" pid-field="pid" ></j-tree-select>
    * */
-  import { ref, watch, unref, onMounted } from 'vue';
+  import { ref } from 'vue';
   import { defHttp } from '/@/utils/http/axios';
   import { propTypes } from '/@/utils/propTypes';
-  import { useAttrs } from '/@/hooks/core/useAttrs';
   import { useMessage } from '/@/hooks/web/useMessage';
-  import { async } from 'rxjs';
 
   enum Api {
     url = '/sys/dict/DeviceKind/query',

+ 7 - 6
src/components/chart/BarAndLine.vue

@@ -7,10 +7,8 @@
 <script lang="ts">
   import { defineComponent, PropType, ref, Ref, reactive, watchEffect, watch, nextTick } from 'vue';
   import { useECharts } from '/@/hooks/web/useECharts';
-  import { toEchartsData } from '/@/utils/ventutil';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
   import EchartsUtil from '/@/utils/echartsUtil';
-import { object } from 'vue-types';
 
   export default defineComponent({
     name: 'BarAndLine',
@@ -58,8 +56,8 @@ import { object } from 'vue-types';
       const option = reactive({
         name: '',
         color: ['#7B68EE', '#0000CD', '#6495ED', '#00BFFF', '#AFEEEE', '#008080', '#00FA9A', '#2E8B57', '#FAFAD2', '#DAA520'],
-        tooltip: null,
-        grid: null,
+        tooltip: {},
+        grid: {},
         toolbox: {
           feature: {
             saveAsImage: {
@@ -72,8 +70,8 @@ import { object } from 'vue-types';
             },
           },
         },
-        dataZoom: null,
-        legend: null,
+        dataZoom: {},
+        legend: {},
         timeline: null,
         xAxis: null,
         yAxis: null,
@@ -96,6 +94,8 @@ import { object } from 'vue-types';
       });
 
       function initChartsOption() {
+        debugger
+
         optionUtil = new EchartsUtil(Object.assign(option, props.option));
         optionUtil.initChartOption(props.chartsType, chartsColumns);
       }
@@ -109,6 +109,7 @@ import { object } from 'vue-types';
             option.series[index].data = props.dataSource.map((item) => item[propType.dataIndex] || 0);
           });
           option.xAxis[0].data = xAxisData;
+          console.log('echarts监测列表数据', option.xAxis[0].data)
           setOptions(option, isRefresh);
         }
       }

+ 97 - 0
src/components/chart/BarAndLineCustom.vue

@@ -0,0 +1,97 @@
+<template>
+  <div ref="chartRef" :style="{ height, width }"></div>
+</template>
+<script lang="ts">
+  import { defineComponent, PropType, ref, Ref, reactive, watchEffect } from 'vue';
+  import { useECharts } from '/@/hooks/web/useECharts';
+
+  export default defineComponent({
+    name: 'BarAndLine',
+    props: {
+      chartData: {
+        type: Array,
+        default: () => [],
+      },
+      option: {
+        type: Object,
+        default: () => ({}),
+      },
+      xAxisPropType: {
+        type: String,
+        required: true,
+      },
+      propTypeArr: {
+        type: Array,
+        default: () => [],
+        required: true,
+      },
+      width: {
+        type: String as PropType<string>,
+        default: '100%',
+      },
+      height: {
+        type: String as PropType<string>,
+        default: '100%',
+      },
+    },
+    setup(props) {
+      const chartRef = ref<HTMLDivElement | null>(null);
+      const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
+      const option = reactive({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'shadow',
+            label: {
+              show: true,
+              backgroundColor: '#333',
+            },
+          },
+        },
+        legend: {
+          top: 10,
+          textStyle: {
+            color: '#ffffffee',
+          },
+        },
+        xAxis: {
+          type: 'category',
+          splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+          data: [],
+        },
+        yAxis: {
+          type: 'value',
+          splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+        },
+        series: [
+          {
+            name: 'bar',
+            type: 'bar',
+            data: [],
+          },
+        ],
+      });
+
+      watchEffect(() => {
+        props.chartData && initCharts();
+      });
+
+      function initCharts() {
+
+        if (props.option) {
+          Object.assign(option, props.option);
+        }
+        //图例类型
+        // let typeArr = Array.from(new Set(props.chartData.map((item) => item.type)));
+        //轴数据
+        let xAxisData = Array.from(new Set(props.chartData.map((item) => item[props.xAxisPropType])));
+        [...props.propTypeArr].forEach((filed:string, index) => {
+          option.series[index]['data'] = props.chartData.map((item:any) => item[filed]);
+        });
+        option.xAxis.data = xAxisData;
+        setOptions(option, false);
+      }
+      return { chartRef };
+    },
+  });
+</script>

+ 4 - 0
src/design/vent/antCss.less

@@ -42,6 +42,10 @@
 .@{ventSpace}-table.@{ventSpace}-table-bordered > .@{ventSpace}-table-container > .@{ventSpace}-table-header > table {
   border-top: 1px solid @vent-table-hover !important;
 }
+.@{ventSpace}-table-cell-scrollbar{
+  box-shadow:none !important;
+}
+
 .@{ventSpace}-table.@{ventSpace}-table-bordered > .@{ventSpace}-table-container {
   border-left: 1px solid @vent-table-hover !important;
 }

+ 9 - 2
src/design/vent/index.less

@@ -128,8 +128,10 @@
     }
     /** 下拉框 */
     .@{ventSpace}-select-dropdown {
-      border-bottom: 1px solid #ececec66;
-      background: transparent !important;
+      // border-bottom: 1px solid #ececec66;
+      // background: transparent !important;
+      border: 1px solid #ececec66;
+      background: #004362 !important;
       left: 0px !important;
       backdrop-filter: blur(50px);
 
@@ -145,6 +147,11 @@
         background-color: #008fc366 !important;
       }
     }
+    .@{ventSpace}-picker-panel{
+      border: 1px solid #ececec66;
+      // background: #004362 !important;
+      color: #fff !important;
+    }
 
     .@{ventSpace}-select-tree {
       background: transparent !important;

+ 6 - 4
src/design/vent/modal.less

@@ -361,12 +361,13 @@
     }
   }
   .bottom-tabs-box {
-    position: absolute;
+    position: fixed;
     width: calc(100% - 10px);
     height: 280px;
     bottom: 20px;
     padding: 0 20px;
     margin: 0 5px;
+    pointer-events: auto;
 
     &:before {
       position: absolute;
@@ -403,8 +404,8 @@
     :deep(.tabs-box) {
       position: absolute;
       width: calc(100% - 46px);
-      bottom: 0;
-      height: 100%;
+      bottom: 0px;
+      height: calc(100% - 0px);
       pointer-events: auto;
       // background: linear-gradient(#00daff33, #2081ff11);
       background: linear-gradient(#0091aa33, #2081ff11);
@@ -421,7 +422,7 @@
       }
       .@{ventSpace}-tabs-content,
       .vent-table {
-        height: 100%;
+        height: calc(100% - 10px);
       }
       .@{ventSpace}-tabs-top > .@{ventSpace}-tabs-nav {
         margin: 0 !important;
@@ -604,6 +605,7 @@
 :deep(.@{ventSpace}-picker),
 :deep(.@{ventSpace}-select-selector) {
   // width: 100% !important;
+  // height: 30px !important;
   background: #00000017 !important;
   border: 1px solid @vent-form-item-boder !important;
   input,

+ 3 - 2
src/enums/pageEnum.ts

@@ -5,8 +5,9 @@ export enum PageEnum {
   // 暂时修改
   // BASE_LOGIN = '/monitor/monitor-fan-main',
   // basic home path
-  BASE_HOME = '/micro-vent-3dModal/dashboard/analysis',
-  // BASE_HOME = '/monitorChannel/monitor-windrect',
+  // BASE_HOME = '/micro-vent-3dModal/dashboard/analysis',
+  // BASE_HOME = '/micro-need-air',
+  BASE_HOME = '/monitorChannel/monitor-windrect',
   // error page path
   ERROR_PAGE = '/exception',
   // error log page path

+ 0 - 9
src/layouts/default/content/index.vue

@@ -54,21 +54,12 @@
               }
             }
           }
-          // const route = unref(currentRoute);
-          // if (route.path.startsWith('/micro-vent-3dModal/modelchannel/safety/VentanalyModel3D') && document.body.getAttribute('class')?.includes('style-styleTwo')) {
-          //   document.body.removeAttribute('class', 'style-styleTwo');
-          // }
         });
       }
       useContentViewHeight();
 
       const getShowFullHeader = computed(() => {
         const route = unref(currentRoute);
-        // if (!route.path.startsWith('/micro-vent-3dModal') || route.path.startsWith('/micro-vent-3dModal/modelchannel/safety/VentanalyModel3D')) {
-        //   if (document.body.getAttribute('class')?.includes('style-styleTwo')) document.body.removeAttribute('class', 'style-styleTwo');
-        // } else {
-        //   document.body.setAttribute('class', 'style-styleTwo');
-        // }
         return getShowFullHeaderRef.value && ((route.path.startsWith('/micro-')));
       });
       onBeforeMount(() => {});

+ 5 - 0
src/layouts/default/header/index.vue

@@ -38,6 +38,11 @@
       </div>
     </div>
   </Header>
+  <div v-else-if="currentRoute.path !== '/micro-vent-3dModal/dashboard/analysis'" :class="`${prefixCls}-action`"  style="position: fixed; top: 30px; right: 20px; z-index: 999;">
+    <div class="right-position">
+      <UserDropDown :theme="getHeaderTheme" />
+    </div>
+  </div>
   <LoginSelect ref="loginSelectRef" @success="loginSelectOk" />
 </template>
 <script lang="ts">

+ 0 - 43
src/router/routes/basic.ts

@@ -78,49 +78,6 @@ export const QIANKUN_ROUTE: AppRouteRecordRaw = {
         },
       ],
     },
-
-    // {
-    //   path: '/micro-vent-3dModal',
-    //   name: QIANKUN_ROUTE_NAME,
-    //   component: QIANKUN_COMPONENT,
-    //   meta: {
-    //     title: '子应用',
-    //     hideBreadcrumb: true,
-    //     hideMenu: true,
-    //   },
-    //   children: [
-    //     {
-    //       path: '/modelchannel/safety/VentanalyModel3D',
-    //       name: QIANKUN_ROUTE_NAME,
-    //       component: import('/@/views/demo/threejs/damper.vue'),
-    //       meta: {
-    //         title: '子应用',
-    //         hideBreadcrumb: true,
-    //         hideMenu: true,
-    //       },
-    //     },
-    //     {
-    //       path: ':path(.*)*',
-    //       name: QIANKUN_ROUTE_NAME,
-    //       component: QIANKUN_COMPONENT,
-    //       meta: {
-    //         title: '子应用',
-    //         hideBreadcrumb: true,
-    //         hideMenu: true,
-    //       },
-    //     },
-    //   ],
-    // },
-    // {
-    //   path: '/micro-3d-modal-network/:path(.*)*',
-    //   name: QIANKUN_ROUTE_NAME,
-    //   component: import('/@/views/demo/threejs/damper.vue'),
-    //   meta: {
-    //     title: '子应用',
-    //     hideBreadcrumb: true,
-    //     hideMenu: true,
-    //   },
-    // },
   ],
 };
 

+ 8 - 5
src/utils/echartsUtil.ts

@@ -57,9 +57,11 @@ export default class echartsUtil {
     dataZoom = this.getDataZoom(type);
 
     if (this.option) {
-      this.option['tooltip'] = tooltip;
+      Object.assign(this.option['tooltip'], tooltip);
+      // this.option['tooltip'] = tooltip;
       this.option['grid'] = grid;
-      this.option['legend'] = this.getLegend(legends);
+      // this.option['legend'] = this.getLegend(legends);
+      Object.assign(this.option['legend'], this.getLegend(legends));
       this.option['xAxis'] = xAxis;
       this.option['yAxis'] = yAxis;
       this.option['series'] = series;
@@ -116,7 +118,7 @@ export default class echartsUtil {
             width: 1, // 这里是为了突出显示加上的
           },
         },
-        splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.5)' } },
+        splitLine: { show: true, lineStyle: { color: 'rgba(21,80,126,.3)', type: 'dashed' } },
         axisLabel: {
           show: true,
           color: '#ffffffbb',
@@ -156,10 +158,11 @@ export default class echartsUtil {
       },
       splitLine: {
         lineStyle: {
-          color: 'rgba(17,60,87,1)',
+          color: 'rgba(21,80,126,.3)',
           type: 'dashed', //设置网格线类型 dotted:虚线   solid:实线
         },
-        show: item.linetype == 'line' ? true : false,
+        // show: item.linetype == 'line' ? true : false,
+        show: true,
       },
       showBackground: true,
       backgroundStyle: {

+ 2 - 2
src/utils/threejs/main.worker.ts

@@ -26,9 +26,9 @@ export function initModalWorker() {
     'ztfj/dj2.glb',
     'ztfj/bg.glb',
     'fire/laneway.glb',
-    'fire/workFace.glb',
+    'fire/chamber.glb',
     'yafeng/nitrogen.glb',
-    'ceshi/glass.glb',
+    // 'ceshi/glass.glb',
   ];
 
   const db: any = new Dexie('DB');

+ 3 - 4
src/utils/threejs/util.ts

@@ -38,7 +38,6 @@ export const getTextCanvas = (w, h, textArr, imgUrl) => {
   canvas.height = height;
   // 设置样式
   ctx.textAlign = 'start';
-  // ctx.fillStyle = 'rgba(44, 62, 80, 0.65)';
   ctx.fillStyle = 'rgba(0, 0, 0, 0)';
   // 创建渐变
   // var gradient=ctx.createLinearGradient(0,0, canvas.width,0);
@@ -88,8 +87,8 @@ export const getTextCanvas = (w, h, textArr, imgUrl) => {
         ctx.lineWidth = 2;
         ctx.font = item.font;
         ctx.fillStyle = item.color;
-        !!item.strokeStyle && (ctx.strokeStyle = item.strokeStyle);
-        ctx.strokeText(item.text, item.x, item.y, 1024);
+        // !!item.strokeStyle && (ctx.strokeStyle = item.strokeStyle);
+        // if (item.strokeStyle) ctx.strokeText(item.text, item.x, item.y, 1024);
         ctx.fillText(item.text, item.x, item.y, 1024);
       });
       resolve(canvas);
@@ -405,7 +404,7 @@ export const updateAxisCenter = (modal, event) => {
   //获得从相机指向鼠标所对应的3D空间点的射线(归一化)
   vector.sub(modal.camera.position).normalize();
 
-  if (event.originalEvent.deltaY < 0) {
+  if (event.originalEvent && event.originalEvent.deltaY && event.originalEvent.deltaY < 0) {
     modal.camera.position.x += vector.x * factor;
     modal.camera.position.y += vector.y * factor;
     modal.camera.position.z += vector.z * factor;

+ 1 - 1
src/views/demo/comp/modal/Modal2.vue

@@ -1,5 +1,5 @@
 <template>
-  <BasicModal @register="register" title="Modal Title" :helpMessage="['提示1', '提示2']" :okButtonProps="{ disabled: true }">
+  <BasicModal @register="register"  title="Modal Title" :helpMessage="['提示1', '提示2']" :okButtonProps="{ disabled: true }">
     <a-button type="primary" @click="closeModal" class="mr-2"> 从内部关闭弹窗 </a-button>
     <a-button type="primary" @click="setModalProps"> 从内部修改title </a-button>
   </BasicModal>

+ 74 - 0
src/views/vent/comment/components/fourBorderBg.vue

@@ -0,0 +1,74 @@
+<template>
+  <div class="win">
+    <!-- 四个角的边框效果 -->
+    <div class="border_corner border_corner_left_top"></div>
+    <div class="border_corner border_corner_right_top"></div>
+    <div class="border_corner border_corner_left_bottom"></div>
+    <div class="border_corner border_corner_right_bottom"></div>
+    <div class="main">
+        <!-- 这里写内容 -->
+        <slot></slot>
+    </div>
+</div>
+</template>
+<script lang="ts">
+import { defineComponent } from 'vue'
+export default defineComponent({
+  name: 'fourBorderBg',
+})
+</script>
+
+<style lang="less" scoped>
+  .win {
+    margin: 20px;
+    position: relative;
+    display: inline-block;
+  }
+  .main {
+    min-width: 60px;
+    border: 1px solid #3DF6FF66;
+    border-radius: 2px;
+    background-color: #001d3055;
+    backdrop-filter: blur(8px);
+    box-shadow: 0 0 10px #333;
+    padding: 5px 8px;
+    color: #ffffffee;
+  }
+  .border_corner{
+    z-index: 2500;
+    position: absolute;
+    width: 8px;
+    height: 8px;
+    background-color: rgba(0,0,0,0);
+    border: 2px solid #3DF6FF;
+  }
+  .border_corner_left_top{
+    top: 0;
+    left: 0;
+    border-right: none;
+    border-bottom: none;
+    border-top-left-radius: 2px;
+  }
+  .border_corner_right_top{
+    top: 0;
+    right: 0;
+    border-left: none;
+    border-bottom: none;
+    border-top-right-radius: 2px;
+  }
+  .border_corner_left_bottom{
+    bottom: 0;
+    left: 0;
+    border-right: none;
+    border-top: none;
+    border-bottom-left-radius: 2px;
+  }
+  .border_corner_right_bottom{
+    bottom: 0;
+    right: 0;
+    border-left: none;
+    border-top: none;
+    border-bottom-right-radius: 2px;
+
+  }
+</style>

+ 0 - 55
src/views/vent/deviceManager/comment/NormalTable.vue

@@ -79,7 +79,6 @@
     },
     batchDelete: {
       type: Function,
-      // required: true,
     },
     saveOrUpdate: {
       type: Function,
@@ -87,7 +86,6 @@
     },
     pointList: {
       type: Function,
-      // required: true,
     },
     showTab: {
       type: Boolean,
@@ -115,7 +113,6 @@
   const [registerModal, { openModal, closeModal }] = useModal();
 
   const columnList = getTableHeaderColumns(props.columnsType);
-  console.log('aaa', columnList);
 
   // 列表页面公共参数、方法
   const { prefixCls, tableContext, onExportXls, onImportXls, doRequest } = useListPage({
@@ -261,71 +258,19 @@
   @ventSpace: zxm;
 
   @vent-table-no-hover: #00bfff10;
-  // :deep(.ant-table-header){
-  //   background-color:transparent;
-  //   height: 0;
-  // }
-  // :deep(.jeecg-basic-table .ant-table-wrapper){
-  //   background-color: #ffffff00;
-  // }
-  // :deep(.ant-table-body) {
-  //   height: auto !important;
-  // }
-  // :deep(.ant-table){
-  //   background-color: #ffffff00 !important;
-  // }
-  // :deep(.ant-table-thead > tr > th){
-  //   background-color:transparent
-  // }
-  // :deep(.ant-table-body > tr > th){
-  //   background-color:transparent
-  // }
-  // :deep(.ant-table-body > tr > td){
-  //   border: none;
-  // }
-  // :deep(.ant-table-fixed-header > .ant-table-content > .ant-table-scroll > .ant-table-body){
-  //   background-color:transparent
-  // }
-  // :deep(.jeecg-basic-table-row__striped td){
-  //   background-color: transparent;
-  // }
   :deep(.@{ventSpace}-table-cell-row-hover) {
     background: #264d8833 !important;
   }
   :deep(.@{ventSpace}-table-row-selected) {
     background: #268bc522 !important;
   }
-  // :deep(.ant-table-tbody) {
-  //   tr.ant-table-row-selected {
-  //     td {
-  //       background: #007cc415 !important;
-  //     }
-  //   }
-  // }
 
   :deep(.@{ventSpace}-table-tbody > tr > td) {
     background-color: #0dc3ff05;
   }
   :deep(.jeecg-basic-table-row__striped) {
-    // background: #97efff11 !important;
     td {
-      // background-color: #97efff11 !important;
       background-color: @vent-table-no-hover !important;
     }
   }
-  // :deep(.ant-table-thead) {
-  //   // background: linear-gradient(#003f77 0%, #004a86aa 10%) !important; //#003f77, #0a134c
-  //   background-color: #3d9dd45d !important;
-  //   & > tr > th,
-  //   .ant-table-column-title {
-  //     // color: #70f9fc !important;
-  //     color: #fff !important;
-  //     border-color: #91e9fe !important;
-  //     border-left: none !important;
-  //     // border-right: none !important;
-  //     &:last-child {
-  //       border-right: none !important;
-  //     }
-  //   }
-  // }
 </style>

+ 0 - 56
src/views/vent/deviceManager/comment/normalBtnTable.vue

@@ -37,8 +37,6 @@
   import { BasicTable, TableAction } from '/@/components/Table';
   import { useModal } from '/@/components/Modal';
   import DeviceModal from './DeviceModal.vue';
-  // import { getToken } from '/@/utils/auth';
-  // import { useGlobSetting } from '/@/hooks/setting';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
   import { useListPage } from '/@/hooks/system/useListPage';
 
@@ -117,7 +115,6 @@
   const [registerModal, { openModal, closeModal }] = useModal();
 
   const columnList = getTableHeaderColumns(props.columnsType);
-  console.log('aaa', columnList);
 
   // 列表页面公共参数、方法
   const { prefixCls, tableContext, onExportXls, onImportXls, doRequest } = useListPage({
@@ -167,7 +164,6 @@
 
   const saveOrUpdateHandler = async (params) => {
     Object.assign(params, { dictId: dictId.value });
-    console.log(params, 'params111');
     try {
       await props.saveOrUpdate(params, isUpdate.value);
       !props.showTab ? closeModal() : '';
@@ -284,71 +280,19 @@
   @ventSpace: zxm;
 
   @vent-table-no-hover: #00bfff10;
-  // :deep(.ant-table-header){
-  //   background-color:transparent;
-  //   height: 0;
-  // }
-  // :deep(.jeecg-basic-table .ant-table-wrapper){
-  //   background-color: #ffffff00;
-  // }
-  // :deep(.ant-table-body) {
-  //   height: auto !important;
-  // }
-  // :deep(.ant-table){
-  //   background-color: #ffffff00 !important;
-  // }
-  // :deep(.ant-table-thead > tr > th){
-  //   background-color:transparent
-  // }
-  // :deep(.ant-table-body > tr > th){
-  //   background-color:transparent
-  // }
-  // :deep(.ant-table-body > tr > td){
-  //   border: none;
-  // }
-  // :deep(.ant-table-fixed-header > .ant-table-content > .ant-table-scroll > .ant-table-body){
-  //   background-color:transparent
-  // }
-  // :deep(.jeecg-basic-table-row__striped td){
-  //   background-color: transparent;
-  // }
   :deep(.@{ventSpace}-table-cell-row-hover) {
     background: #264d8833 !important;
   }
   :deep(.@{ventSpace}-table-row-selected) {
     background: #268bc522 !important;
   }
-  // :deep(.ant-table-tbody) {
-  //   tr.ant-table-row-selected {
-  //     td {
-  //       background: #007cc415 !important;
-  //     }
-  //   }
-  // }
 
   :deep(.@{ventSpace}-table-tbody > tr > td) {
     background-color: #0dc3ff05;
   }
   :deep(.jeecg-basic-table-row__striped) {
-    // background: #97efff11 !important;
     td {
-      // background-color: #97efff11 !important;
       background-color: @vent-table-no-hover !important;
     }
   }
-  // :deep(.ant-table-thead) {
-  //   // background: linear-gradient(#003f77 0%, #004a86aa 10%) !important; //#003f77, #0a134c
-  //   background-color: #3d9dd45d !important;
-  //   & > tr > th,
-  //   .ant-table-column-title {
-  //     // color: #70f9fc !important;
-  //     color: #fff !important;
-  //     border-color: #91e9fe !important;
-  //     border-left: none !important;
-  //     // border-right: none !important;
-  //     &:last-child {
-  //       border-right: none !important;
-  //     }
-  //   }
-  // }
 </style>

+ 0 - 2
src/views/vent/deviceManager/equipManager/equip.data.ts

@@ -1,7 +1,5 @@
 import { BasicColumn } from '/@/components/Table';
 import { FormSchema } from '/@/components/Table';
-// import { queryDeviceList } from './point.api';
-// import { defHttp } from '/@/utils/http/axios';
 
 export const columns: BasicColumn[] = [
   {

+ 1 - 25
src/views/vent/deviceManager/pointTabel/point.data.ts

@@ -9,31 +9,7 @@ export const columns: BasicColumn[] = [
     dataIndex: 'devicekind_dictText',
     width: 120,
   },
-  // {
-  //   title: '设备类型code',
-  //   dataIndex: 'devicekind',
-  //   width: 120,
-  // },
-  // {
-  //   title: 'plc地址',
-  //   dataIndex: 'plcaddr',
-  //   width: 100,
-  // },
-  // {
-  //   title: 'plc读写位数',
-  //   dataIndex: 'floatnum',
-  //   width: 100,
-  //   // customRender: render.renderAvatar,
-  // },
-  // {
-  //   title: '读写类型',
-  //   dataIndex: 'datakind_dictText',
-  //   width: 80,
-  //   // sorter: true,
-  //   // customRender: ({ text }) => {
-  //   //   return render.renderDict(text, 'sex');
-  //   // },
-  // },
+ 
   {
     title: '值名称',
     dataIndex: 'valuename',

+ 9 - 0
src/views/vent/deviceManager/workingFace/workingFace.data.ts

@@ -127,6 +127,15 @@ export const formSchema: FormSchema[] = [
     },
   },
   {
+    label: '监测类型',
+    field: 'monitorflag_dictText',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'monitorflag',
+      placeholder: '请选择状态',
+    },
+  },
+  {
     label: '风向',
     field: 'windkind',
     component: 'JDictSelectTag',

+ 18 - 0
src/views/vent/monitorManager/chamberMonitor/chamber.api.ts

@@ -0,0 +1,18 @@
+import { defHttp } from '/@/utils/http/axios';
+import { Modal } from 'ant-design-vue';
+
+enum Api {
+  list = '/monitor/device',
+  baseList = '/safety/ventanalyWindow/list',
+}
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });
+
+/**
+ * 保存或者更新用户
+ * @param params
+ */
+export const getTableList = (params) => defHttp.get({ url: Api.baseList, params });

+ 0 - 0
src/views/vent/monitorManager/chamberMonitor/chamber.data.ts


+ 107 - 0
src/views/vent/monitorManager/chamberMonitor/chamber.threejs.base.ts

@@ -0,0 +1,107 @@
+import * as THREE from 'three';
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class ChamberBase {
+  model;
+  modelName = 'chamber';
+  group: THREE.Object3D | null = null;
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
+    directionalLight.position.set(-0.8, 23, 3.9);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    // gui.add(directionalLight.position, 'x', -10, 20).onChange(function (value) {
+    //   directionalLight.position.x = Number(value);
+    //   _this.render();
+    // });
+    // gui.add(directionalLight.position, 'y', -50, 50).onChange(function (value) {
+    //   directionalLight.position.y = Number(value);
+    //   _this.render();
+    // });
+    // gui.add(directionalLight.position, 'z', -20, 20).onChange(function (value) {
+    //   directionalLight.position.z = Number(value);
+    //   _this.render();
+    // });
+    // const pointLight5 = new THREE.PointLight(0xffffff, 0.8, 120);
+    // pointLight5.position.set(-54, 30, 23.8);
+    // pointLight5.shadow.bias = 0.05;
+    // this.group.add(pointLight5);
+
+    // const pointLight7 = new THREE.PointLight(0xffffff, 1, 1000);
+    // pointLight7.position.set(45, 51, -4.1);
+    // pointLight7.shadow.bias = 0.05;
+    // this.model.scene.add(pointLight7);
+
+    const spotLight = new THREE.SpotLight();
+    spotLight.angle = Math.PI / 2;
+    spotLight.penumbra = 0;
+    spotLight.castShadow = true;
+    spotLight.intensity = 1;
+
+    spotLight.shadow.camera.near = 0.5; // default
+    spotLight.shadow.focus = 1.2;
+    spotLight.shadow.bias = -0.000002;
+
+    spotLight.position.set(-7.19, 199, -68.1);
+    // this.group.add(spotLight);
+
+    // gui.add(directionalLight.position, 'x', -10, 20).onChange(function (value) {
+    //   directionalLight.position.x = Number(value);
+    //   _this.render();
+    // });
+    // gui.add(directionalLight.position, 'y', -50, 50).onChange(function (value) {
+    //   directionalLight.position.y = Number(value);
+    //   _this.render();
+    // });
+    // gui.add(directionalLight.position, 'z', -20, 20).onChange(function (value) {
+    //   directionalLight.position.z = Number(value);
+    //   _this.render();
+    // });
+
+    // gui.add(spotLight.position, 'x', -600, 600).onChange(function (value) {
+    //   spotLight.position.x = Number(value);
+    //   _this.render();
+    // });
+    // gui.add(spotLight.position, 'y', -600, 800).onChange(function (value) {
+    //   spotLight.position.y = Number(value);
+    //   _this.render();
+    // });
+    // gui.add(spotLight.position, 'z', -500, 1000).onChange(function (value) {
+    //   spotLight.position.z = Number(value);
+    //   _this.render();
+    // });
+  }
+
+  addChamberText(selectData) {
+    //
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setModel([this.modelName]).then((gltf) => {
+        this.group = gltf[0];
+        if (this.group) {
+          this.group?.scale.set(0.1, 0.1, 0.1);
+          this.group.position.y += 60;
+          resolve(null);
+          this.addLight();
+        }
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+export default ChamberBase;

+ 115 - 0
src/views/vent/monitorManager/chamberMonitor/chamber.threejs.ts

@@ -0,0 +1,115 @@
+import * as THREE from 'three';
+import UseThree from '../../../../utils/threejs/useThree';
+import ChamberBase from './chamber.threejs.base';
+import { animateCamera } from '/@/utils/threejs/util';
+import { useAppStore } from '/@/store/modules/app';
+
+// 模型对象、 文字对象
+let model,
+  chamberBaseObj: ChamberBase,
+  group,
+  chamberType = 'chamberBase'; // workerFaceFiber
+const appStore = useAppStore();
+
+// 鼠标点击事件
+const mouseEvent = (event) => {
+  event.stopPropagation();
+  const widthScale = appStore.getWidthScale;
+  const heightScale = appStore.getHeightScale;
+  // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
+  model.mouse.x =
+    ((-model.canvasContainer.getBoundingClientRect().left * widthScale + event.clientX) / (model.canvasContainer.clientWidth * widthScale)) * 2 - 1;
+  model.mouse.y =
+    -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
+  (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
+  if (group) {
+    if (chamberType === 'chamberBase') {
+      // chamberBaseObj.mousedownModel.call(chamberBaseObj, model.rayCaster);
+    }
+
+    // const intersects = model.rayCaster?.intersectObjects([...group.children]) as THREE.Intersection[];
+    // if (intersects.length > 0) {
+    //   if (fiberType === 'beltFiber') {
+    //     beltFiberObj.mousedownModel.call(beltFiberObj, intersects);
+    //   } else if (fiberType === 'workFace') {
+    //     workerFaceFiberObj.mousedownModel.call(workerFaceFiberObj, intersects);
+    //   }
+    // }
+
+    console.log('摄像头,控制器------>', model.camera, model.orbitControls);
+  }
+};
+
+const addMouseEvent = () => {
+  // 定义鼠标点击事件
+  model.canvasContainer?.addEventListener('mousedown', mouseEvent.bind(null));
+};
+
+const render = () => {
+  if (model.animationId != -1) {
+    model.animationId = requestAnimationFrame(render);
+    model.css3dRender?.render(model.scene as THREE.Scene, model.camera as THREE.PerspectiveCamera);
+    model.stats?.update();
+  }
+};
+
+export const addChamberText = (selectData) => {
+  if (chamberType === 'chamberBase') {
+    return chamberBaseObj.addChamberText.call(chamberBaseObj, selectData);
+  }
+};
+
+// 切换模型类型
+export const setModelType = (type) => {
+  chamberType = type;
+  return new Promise((resolve) => {
+    if (chamberType === 'chamberBase') {
+      group = chamberBaseObj.group;
+      const oldCameraPosition = { x: 124.736, y: 63.486, z: 103.337 };
+      model.scene.add(chamberBaseObj.group);
+      model.camera.position.set(0, 0, 300);
+      setTimeout(async () => {
+        // const position = { x: 0, y: 3.8, z: 10.5 };
+        await animateCamera(
+          oldCameraPosition,
+          oldCameraPosition,
+          { x: 1.6659700995438462, y: 315.8350412885176, z: 568.1266662409791 },
+          { x: 1.6659700995440048, y: -32.575630674334704, z: 22.306948260174813 },
+          model,
+          0.8
+        );
+      }, 300);
+
+      resolve(null);
+    }
+  });
+};
+
+export const mountedThree = () => {
+  return new Promise(async (resolve) => {
+    model = new UseThree('#chamber3D');
+    model.setEnvMap('test1');
+    model.renderer.toneMappingExposure = 1;
+    // model.camera.position.set(100, 0, 1000);
+
+    chamberBaseObj = new ChamberBase(model);
+    await chamberBaseObj.mountedThree();
+
+    // model.scene.add(chamberBaseObj.group);
+
+    addMouseEvent();
+    // render();
+    model.animate();
+    resolve(null);
+  });
+};
+
+export const destroy = () => {
+  if (model) {
+    chamberBaseObj.destroy();
+    model.deleteModal();
+    model = null;
+    group = null;
+    chamberBaseObj = null;
+  }
+};

+ 212 - 0
src/views/vent/monitorManager/chamberMonitor/index.vue

@@ -0,0 +1,212 @@
+<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="chamber3D" 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="title-text">
+      {{ selectData.strname }}
+    </div>
+    <div class="center-container">
+      <div class="lr left-box"></div>
+      <div class="lr right-box">
+        <div class="">
+
+        </div>
+        <div class="">
+
+        </div>
+      </div>
+    </div>
+    <div class="bottom-tabs-box">
+      <MonitorTable columnsType="fiber_monitor" :dataSource="fiberDataSource" @selectRow="getSelectRow"
+        design-scope="fiber-monitor" title="风窗监测" :scroll="{y: 240}" :isShowPagination="false">
+        <template #filterCell="{ column, record }">
+          <a-tag v-if="column.dataIndex === 'warnFlag'" :color="record.warnFlag == 0 ? 'green' : 'red'">{{
+            record.warnFlag == 0 ? '正常' : '报警'
+          }}</a-tag>
+          <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == 0 ? 'default' : 'green'">{{
+            record.netStatus == 0 ? '断开' : '连接'
+          }}</a-tag>
+          <div v-if="record.nwindownum == 1 && column.dataIndex === 'rearArea'">/</div>
+        </template>
+      </MonitorTable>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+// import { message } from 'ant-design-vue';
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, toRaw } from 'vue';
+import MonitorTable from '../comment/MonitorTable.vue';
+import { mountedThree, destroy, addChamberText, setModelType } from './chamber.threejs';
+import { list } from './chamber.api';
+import lodash from 'lodash';
+
+const activeKey = ref('1');
+const loading = ref(false);
+
+// 默认初始是第一行
+const selectRowIndex = ref(0);
+const dataSource = ref([])
+const fiberDataSource = ref([]); //dusting
+const dustDataSource = ref([]); 
+
+const tabChange = (activeKeyVal) => {
+  activeKey.value = activeKeyVal;
+};
+
+const initData = {
+  deviceID: '',
+  deviceType: '',
+  strname: '',
+};
+
+// 监测数据
+const selectData = reactive(lodash.cloneDeep(initData));
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+const getMonitor = () => {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      const data = await getSysDataSource();
+      Object.assign(selectData, data);
+
+      if (timer) {
+        timer = null;
+      }
+      getMonitor();
+    }, 1000);
+  }
+};
+
+const getSysDataSource = async () => {
+  const res = await list({ devicetype: 'sys_dongshi', pagetype: 'normal' });
+  dataSource.value = res.msgTxt[0].datalist || [];
+  dataSource.value.forEach((data: any) => {
+    const readData = data.readData;
+    data = Object.assign(data, readData);
+  });
+  const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
+  return data;
+};
+
+const getDataSource = async (systemID) => {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt[0];
+  result.forEach(item => {
+    if (item.type === 'dusting_auto') {
+      // 喷粉
+      dustDataSource.value = item.filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'fiber_normal') {
+      // 光纤
+      fiberDataSource.value = item.filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'sys') {
+      // 硐室基本
+      // fiberDataSource.value = item.filter((data: any) => {
+      //   const readData = data.readData;
+      //   return Object.assign(data, readData);
+      // })
+    }
+  })
+}
+
+
+// 切换检测数据
+const getSelectRow = (selectRow, index) => {
+  if (!selectRow) return;
+  selectRowIndex.value = index;
+
+  Object.assign(selectData, initData, selectRow);
+  getDataSource(selectData.deviceID)
+  // setModelType(type).then(() => {
+   
+  // });
+}
+
+onBeforeMount(() => {
+
+});
+
+onMounted(() => {
+  loading.value = true;
+  mountedThree().then(async () => {
+    await setModelType('chamberBase');
+    loading.value = false;
+    getMonitor();
+  });
+});
+onUnmounted(() => {
+  destroy();
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+</script>
+<style lang="less" scoped>
+@import '/@/design/vent/modal.less';
+@ventSpace: zxm;
+
+.center-container{
+  width: 100%;
+  height: 550px;
+  border: 1px solid #fff;
+  margin-top: 30px;
+  display: flex;
+  justify-content: space-between;
+  .lr{
+    width: 250px;
+    height: 100%;
+    border: 1px solid #73e8fe;
+    display: flex;
+    flex-direction: column;
+  }
+  .right-box{
+    width: 280px;
+  }
+}
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  overflow: auto;
+}
+
+.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>

+ 8 - 0
src/views/vent/monitorManager/comment/AlarmHistoryTable.vue

@@ -29,6 +29,10 @@
     designScope: {
       type: String,
     },
+    scroll: {
+      type: Object,
+      default: () => { }
+    }
   });
 
   const columns = getTableHeaderColumns(props.columnsType);
@@ -42,6 +46,7 @@
       showActionColumn: false,
       bordered: false,
       size: 'small',
+      scroll: props.scroll,
       formConfig: {
         labelAlign: 'left',
         showAdvancedButton: false,
@@ -92,6 +97,9 @@
   :deep(.ventSpace-table-body) {
     height: auto !important;
   }
+  :deep(.zxm-picker){
+      height: 30px !important;
+  }
   .alarm-history-table {
     width: 100%;
     :deep(.jeecg-basic-table-form-container) {

+ 2 - 3
src/views/vent/monitorManager/comment/DeviceEcharts.vue

@@ -10,7 +10,7 @@
       <BarAndLine
         :chartsColumnsType="chartsColumnsType"
         :xAxisPropType="xAxisPropType"
-        :dataSource="resultDataSource"
+        :dataSource="dataSource"
         height="100%"
         :chartsColumns="chartsColumns"
         chartsType="listMonitor"
@@ -149,13 +149,12 @@
         console.log('Page: ', pageNumber);
       };
       watch(
-        [chartsType, deviceId, historyParams, pageSize, currentPage],
+        [chartsType, deviceId, historyParams, pageSize, currentPage,],
         async (
           [newChartsType, newDeviceId, newHistoryParams, newPageSize, newCurrentPage],
           [oldChartsType, oldDeviceId, oldHistoryParams, oldPageSize, oldCurrentPage]
         ) => {
           console.log('[ historyParams ] >', historyParams.ttime, dayjs(historyParams.ttime).format('HH:mm:ss'));
-
           if (newChartsType === 'listMonitor') {
             // 实时监测所有
             resultDataSource.value = props.dataSource;

+ 16 - 4
src/views/vent/monitorManager/comment/HandlerHistoryTable.vue

@@ -6,11 +6,13 @@
 
 <script lang="ts" name="system-user" setup>
   //ts语法
+  import { watch } from 'vue';
   import { BasicTable } from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
   import { defHttp } from '/@/utils/http/axios';
 
+
   const list = (params) => defHttp.get({ url: '/safety/ventanalyDevicesetLog/list', params });
 
   const props = defineProps({
@@ -29,8 +31,12 @@
     designScope: {
       type: String,
     },
+    scroll: {
+      type: Object,
+      default: () => {}
+    }
   });
-
+  
   const columns = getTableHeaderColumns(props.columnsType);
   // 列表页面公共参数、方法
   const { tableContext } = useListPage({
@@ -42,6 +48,7 @@
       showActionColumn: false,
       bordered: false,
       size: 'small',
+      scroll: props.scroll,
       formConfig: {
         labelAlign: 'left',
         showAdvancedButton: false,
@@ -82,14 +89,18 @@
     },
   });
   //注册table数据
-  const [registerTable] = tableContext;
+  const [registerTable, { reload }] = tableContext;
+  
 </script>
 
 <style scoped lang="less">
   @ventSpace: zxm;
 
-  :deep(.@{ventSpace}-table-body) {
-    height: auto !important;
+  // :deep(.@{ventSpace}-table-body) {
+  //   height: auto !important;
+  // }
+  :deep(.zxm-picker){
+      height: 30px !important;
   }
   .handler-history-table {
     width: 100%;
@@ -101,6 +112,7 @@
         .@{ventSpace}-picker,
         .@{ventSpace}-select-selector {
           width: 100% !important;
+          height: 100%;
           background: #00000017;
           border: 1px solid #b7b7b7;
           input,

+ 9 - 1
src/views/vent/monitorManager/comment/HistoryTable.vue

@@ -10,7 +10,7 @@
 
 <script lang="ts" name="system-user" setup>
   //ts语法
-  import { watchEffect, ref, reactive } from 'vue';
+  import { watchEffect, ref } from 'vue';
   import { BasicTable } from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
@@ -35,6 +35,10 @@
     designScope: {
       type: String,
     },
+    scroll: {
+      type: Object,
+      default: () => { }
+    }
   });
 
   const columns = getTableHeaderColumns(props.columnsType);
@@ -49,6 +53,7 @@
       showActionColumn: false,
       bordered: false,
       size: 'small',
+      scroll: props.scroll,
       formConfig: {
         labelAlign: 'left',
         showAdvancedButton: false,
@@ -163,6 +168,9 @@
   :deep(.@{ventSpace}-table-body) {
     height: auto !important;
   }
+  :deep(.zxm-picker){
+      height: 30px !important;
+  }
   .history-table {
     width: 100%;
     :deep(.jeecg-basic-table-form-container) {

+ 6 - 11
src/views/vent/monitorManager/comment/MonitorTable.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="vent-table">
-    <BasicTable ref="ventTableRef" @register="registerTable" :rowSelection="props.isShowSelect ? rowSelection: undefined" :scroll="scroll" :pagination="false" :loading="loading">
+    <BasicTable ref="ventTableRef" @register="registerTable" :rowSelection="props.isShowSelect ? rowSelection: undefined" :loading="loading">
       <template #tableTitle>
         <div></div>
       </template>
@@ -22,12 +22,8 @@
   import { defineExpose, toRaw, watch, ref, onMounted, onUnmounted } from 'vue';
   import { BasicTable } from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage';
-  import { list, deleteUser, batchDeleteUser, getImportUrl, getExportUrl, frozenBatch, syncUser } from '../../../system/user/user.api';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
   import { findIndex } from 'lodash-es';
-  import { computed } from '@vue/reactivity';
-import { number } from 'vue-types';
-  const listApi = '/monitor/device';
   const props = defineProps({
     columnsType: {
       type: String,
@@ -68,12 +64,11 @@ import { number } from 'vue-types';
     },
   });
   const emits = defineEmits(['selectRow']);
-  const dataTableSource = ref([]);
+  const dataTableSource = ref<any[]>([]);
   const loading = ref(true);
 
   const ventTableRef = ref();
-  // 默认初始是第一行
-  const selectRowIndex = ref(0);
+
   const tableMaxHeight = 150;
   const columns = ref([])
   
@@ -86,7 +81,7 @@ import { number } from 'vue-types';
         // 第一次
         setSelectedRowKeys([newVal[0].deviceID]);
       }
-      const list = [];
+      const list = <any[]>[];
       newVal.forEach((item) => {
         list.push(toRaw(item));
       });
@@ -111,7 +106,6 @@ import { number } from 'vue-types';
     designScope: props.designScope,
     tableProps: {
       title: props.title,
-      // api: list,
       dataSource: dataTableSource,
       columns: columns,
       rowSelection: { type: props.isShowSelect? 'radio': undefined },
@@ -121,6 +115,7 @@ import { number } from 'vue-types';
       showActionColumn: props.isShowActionColumn,
       maxHeight: tableMaxHeight,
       bordered: false,
+      scroll: props.scroll,
       rowKey: 'deviceID',
       // striped: true,
       actionColumn: {
@@ -138,7 +133,7 @@ import { number } from 'vue-types';
   });
 
   //注册table数据
-  const [registerTable, { reload, setLoading, setSelectedRowKeys }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
+  const [registerTable, { reload, setLoading, setSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
   watch(
     selectedRowKeys,
     (oldKeys, newKeys) => {

+ 20 - 0
src/views/vent/monitorManager/deviceMonitor/device.api.ts

@@ -0,0 +1,20 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  list = '/monitor/device',
+  baseList = '/safety/ventanalyDeviceInfo/list',
+  deviceTypeList = '/sys/dict/DeviceKind/query',
+}
+/**
+ * 列表接口
+ * @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 });

+ 5 - 0
src/views/vent/monitorManager/deviceMonitor/device.data.ts

@@ -0,0 +1,5 @@
+export const chartsColumns = (deviceType) => {
+  if(deviceType === ''){
+    return []
+  }
+}

+ 271 - 0
src/views/vent/monitorManager/deviceMonitor/index.vue

@@ -0,0 +1,271 @@
+<template>
+  <div class="scene-box">
+    <div class="device-header">智能通风管控系统</div>
+    <div class="device-select-box">
+      <a-tree
+        :show-line="true"
+        :tree-data="treeData"
+        @select="onSelect"
+      >
+      </a-tree>
+    </div>
+    <div class="bottom-tabs-box" @mousedown="setDivHeight" id="monitorBox">
+      <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange" >
+        <a-tab-pane key="1" tab="实时监测">
+          <template v-if="deviceType == 'fan'">
+            <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
+          </template>
+          <template v-else>
+            <MonitorTable
+              :columnsType="`${deviceType}_monitor`"
+              :dataSource="dataSource"
+              design-scope="device_monitor"
+              :isShowPagination = "false"
+              :isShowActionColumn="true"
+              title="设备监测"
+            >
+            <template #action="{ record }">
+              <TableAction
+                :actions="[
+                    {
+                      label: '详情',
+                      onClick: goDetail.bind(null, record),
+                    },
+                    {
+                      label: '定位',
+                      onClick: goLocation.bind(null, record),
+                    },
+                  ]"
+              />
+            </template>
+            </MonitorTable>
+          </template> 
+        </a-tab-pane>
+        <a-tab-pane key="2" tab="历史数据">
+          <div class="tab-item">
+            <HistoryTable :columns-type="`${deviceType}_history`" :device-type="deviceType" :device-list-api="getDeviceList.bind(null, { devicekind : deviceType})" designScope="device-history" />
+          </div>
+        </a-tab-pane>
+        <a-tab-pane key="3" tab="报警历史">
+          <div class="tab-item">
+            <AlarmHistoryTable columns-type="alarm_history" :device-type="deviceType" :device-list-api="getDeviceList.bind(null, { devicekind: deviceType })" designScope="alarm-history" />
+          </div>
+        </a-tab-pane>
+        <a-tab-pane key="4" tab="操作历史">
+          <div class="tab-item">
+            <HandlerHistoryTable columns-type="operatorhistory" :device-type="deviceType"  :device-list-api="getDeviceList.bind(null, { devicekind: deviceType })" designScope="operator-history" />
+          </div>
+        </a-tab-pane>
+      </a-tabs>
+    </div>
+    <component :is="currentModal" v-model:visible="modalVisible" :dataSource="dataSource" :activeID="activeID" />
+  </div>
+</template>
+<script setup lang="ts">
+  import {ref, onMounted, onUnmounted, ComponentOptions, shallowRef } from 'vue'
+  import { list, getDeviceList, getDeviceTypeList } from './device.api'
+  import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
+  import HistoryTable from '../comment/HistoryTable.vue';
+  import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
+  import MonitorTable from '../comment/MonitorTable.vue';
+  import GroupMonitorTable from '../comment/GroupMonitorTable.vue';
+  import type { TreeProps } from 'ant-design-vue';
+  import { TableAction } from '/@/components/Table';
+  import FiberModal from './modal/fiber.modal.vue';
+  import DustModal from './modal/dust.modal.vue'
+
+  // 模态框
+  const currentModal = shallowRef<Nullable<ComponentOptions>>(null);
+  const modalVisible = ref<Boolean>(false);
+
+  //
+  const drawerHeight = ref(700) 
+  
+  const activeKey = ref('1');
+  const dataSource = shallowRef([])
+  const activeID = ref('')
+  const deviceType = ref('window')
+  const scroll = ref({
+    y: drawerHeight.value - 100
+  })
+
+  const treeData = ref<TreeProps['treeData']>([]);
+  const onSelect: TreeProps['onSelect'] = (selectedKeys) => {
+    // console.log('selected', selectedKeys, info);
+    // info.node.title
+    deviceType.value = selectedKeys[0]
+
+  };
+  
+  function tabChange(activeKeyVal) {
+    activeKey.value = activeKeyVal;
+  };
+  
+  async function getDeviceType () {
+    const result = await getDeviceTypeList({})
+    if (result.length > 0) {
+      const dataSource = <TreeProps['treeData']>[]
+      const getData = (resultList, dataSourceList) => {
+        resultList.forEach((item) => {
+
+          if (item.children && item.children.length > 0) {
+            const children = getData(item.children, [])
+            dataSourceList.push({
+              children: children,
+              title: item.itemText,
+              key: item.itemValue,
+            });
+            
+          } else {
+            dataSourceList.push({
+              title: item.itemText,
+              key: item.itemValue,
+              children: []
+            });
+          }
+        });
+        return dataSourceList
+      }
+      treeData.value = getData(result, dataSource)
+    }
+  }
+
+  // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  function getMonitor() {
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = setTimeout(async () => {
+        const res = await list({ devicetype: deviceType.value, pagetype: 'normal' });
+        debugger
+        dataSource.value = res.msgTxt[0].datalist || [];
+        dataSource.value.filter((data: any) => {
+          const readData = data.readData;
+          return Object.assign(data, readData);
+        });
+
+        if (timer) {
+          timer = null;
+        }
+        getMonitor();
+      }, 1000);
+    }
+  };
+
+  function setDivHeight(e: MouseEvent) {
+    const divObject = document.getElementById('monitorBox') as HTMLElement
+    const divHeight = divObject.offsetHeight
+    drawerHeight.value = divHeight
+    const startY = e.clientY
+    document.onmousemove = function(res){
+      res.preventDefault()
+      const distY = Math.abs(res.clientY - startY)
+      if(res.clientY > startY){
+        if(divHeight - distY >= 300){
+          drawerHeight.value = divHeight - distY
+        }else{
+          drawerHeight.value = 300
+        }
+      }
+      if(res.clientY < startY){
+        drawerHeight.value = divHeight + distY
+      }
+      divObject.style.height = drawerHeight.value+'px'
+    }
+    document.onmouseup = function() {
+      document.onmousemove = null
+      if(scroll.value.y != drawerHeight.value - 100) {
+        scroll.value = {y: drawerHeight.value - 100 }
+
+        // const tableBody =  document.getElementsByClassName('zxm-table-container')[0].children[1] as HTMLElement
+        // debugger
+        // tableBody.style.height = `${drawerHeight.value - 350}px`
+      }
+    }
+  }
+
+  function goLocation() {
+
+  }
+  function goDetail(record){
+    if(deviceType.value.startsWith('fiber')){
+      activeID.value = record.deviceID
+      currentModal.value = FiberModal
+      modalVisible.value = true;
+    }
+    if (deviceType.value.startsWith('dusting')) {
+      activeID.value = record.deviceID
+      currentModal.value = DustModal
+      modalVisible.value = true;
+    }
+  }
+
+  onMounted(async() => {
+    await getDeviceType()
+    getMonitor()
+  })
+  onUnmounted(() => {
+    if (timer) {
+      clearTimeout(timer);
+      timer = undefined;
+    }
+  })
+
+</script>
+<style lang="less" scoped >
+  @import '/@/design/vent/modal.less';
+  @ventSpace: zxm;  
+  .device-header{
+    position: fixed;
+    width: 100%;
+    height: 56px;
+    background: url('/@/assets/images/vent/home/modal-top.png');
+    text-align: center;
+    line-height: 56px;
+    font-size: 28px;
+    color: #ffffffdd;
+    font-weight: 600;
+    z-index: -1;
+  }
+  .device-select-box{
+    width: 250px;
+    height: 500px;
+    position: fixed;
+    top: 55px;
+    left: 0;
+    color: #fff;
+    pointer-events: auto;
+    overflow-y: auto;
+    :deep(.zxm-tree){
+      background: transparent !important;
+      color: #fff !important;
+      .zxm-tree-switcher{
+        background: transparent !important;
+      }
+      .zxm-tree-node-content-wrapper.zxm-tree-node-selected{
+        background-color: #00b1c8;
+      }
+      .zxm-tree-node-content-wrapper:hover{
+        background-color: #00b1c8;
+      }
+      input{
+        height: 0px !important;
+      }
+    }
+    &::-webkit-scrollbar-track {
+      -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+      border-radius: 10px;
+      background: #ededed22;
+    }
+    &::-webkit-scrollbar-thumb {
+      -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+      background: #4288A444;
+    }
+  }
+  :deep(.@{ventSpace}-tabs-tabpane-active) {
+    overflow: auto;
+    // height: 100%;
+  }
+  :deep(.zxm-select-dropdown){
+    left: 0 !important;
+  }
+</style>

+ 380 - 0
src/views/vent/monitorManager/deviceMonitor/modal/dust.modal.vue

@@ -0,0 +1,380 @@
+<template>
+  <BasicModal v-bind="$attrs" destroyOnClose @register="register" :title="`粉尘监测详情    ${currentTime}`" width="1200px" >
+    <div class="fiber-modal">
+      <div class="modal-left">
+        <div v-for="device in deviceList" class="link-item" :class="{'active-device-title': device.deviceID === activeDeviceID }" :key="device.deviceID">
+          <span class="" @click="selectDevice(device.deviceID)">{{ device.stationname }}</span>
+        </div>
+      </div>
+      <div class="modal-right">
+        <div class="right-top">
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style max-temperature" size="38" name="max-temperature.svg" />
+            </div>
+            <div class="item-container">
+              <div class="title">巷道温度</div>
+              <div class="value">{{ dustMonitor.temperature }} <span>℃</span> </div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style min-temperature" size="38" name="min-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">粉尘浓度</div>
+              <div class="value">{{ dustMonitor.humidity }} <span>mg/m³</span></div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style aveg-temperature" size="38" name="aveg-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">喷雾水压</div>
+              <div class="value">{{ dustMonitor.waterPressure }} <span>MPa</span></div>
+            </div>
+          </div>
+          <div class="top-item warning-box">
+            <div class="icon">
+              <SvgIcon class="icon-style" size="38" name="risk-level" />
+            </div>
+            <div class="item-container">
+              <div class="title">喷雾装置</div>
+              <div class="warning-value">低风险</div>
+            </div>
+          </div>
+        </div>
+        <div class="right-center">
+          <span class="base-title">粉尘实时监测</span>
+          <div class="dust-group">
+            <div class="dust-item">
+              <div>粉尘浓度(实时)</div>
+              <div>{{ dustMonitor.breathWeighted }}</div>
+            </div>
+            <div class="dust-item">
+              <div>总尘浓度(时间加权)</div>
+              <div>{{ dustMonitor.totalDust }}</div>
+            </div>
+            <div class="dust-item">
+              <div>呼吸加权容许浓度</div>
+              <div>{{ dustMonitor.breathWeighted }}</div>
+            </div>
+            <div class="dust-item">
+              <div>爆炸浓度(煤尘)</div>
+              <div>{{ dustMonitor.dustval }}</div>
+            </div>
+          </div> 
+        </div>
+        <div class="right-bottom">
+          <span class="base-title">测点监测曲线</span>
+          <div class="echarts-box">
+            <BarAndLine
+              xAxisPropType="pos"
+              :dataSource="posList"
+              height="100%"
+              :chartsColumns="chartsColumns"
+              :option="echatsOption"
+              chartsType="listMonitor" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+import { defineComponent, ref, watch, shallowRef, reactive } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import BarAndLine from '/@/components/chart/BarAndLine.vue';
+import { SvgIcon } from '/@/components/Icon';
+import { Decoration7 as DvDecoration7, ScrollBoard as DvScrollBoard } from '@kjgl77/datav-vue3';
+import dayjs from 'dayjs'
+
+export default defineComponent({
+  components: { BasicModal, BarAndLine, SvgIcon, DvScrollBoard, DvDecoration7 },
+  props: {
+    dataSource: {type: Array},
+    activeID: {type: String}
+  },
+  setup(props) {
+    const currentTime = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))
+    const modelRef = ref({});
+    const loading = ref(true);
+    const activeDeviceID = ref('');
+    const deviceList = ref<any[]>([])
+    const posList = ref<any[]>([])
+    const dustMonitor = shallowRef({})
+
+    const echatsOption = {
+      grid: {
+        top: '20%',
+        left: '2px',
+        right: '10px',
+        bottom: '3%',
+        containLabel: true
+      },
+      toolbox: {
+        feature: {}
+      }
+    }
+
+    const chartsColumns = [
+      {
+        legend: '测点温度',
+        seriesName: '(℃)',
+        ymax: 200,
+        yname: '℃',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#FDB146',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'value',
+      },
+    ]
+
+    const columns = [
+      {
+        title: '安装位置',
+        dataIndex: 'position',
+        width: 60,
+        align: 'center',
+        customRender: ({ index }) => {
+          return `测点${index}`
+        }
+      },
+      {
+        title: '安装距离(m)',
+        dataIndex: 'pos',
+        align: 'center',
+        width: 60,
+      },
+      {
+        title: '测点温度',
+        dataIndex: 'value',
+        align: 'center',
+        width: 50,
+      },
+      {
+        title: '测点状态',
+        dataIndex: 'state',
+        align: 'center',
+        width: 50,
+        customRender: () => {
+          return `正常`
+        }
+      },
+    ];
+
+    const warningConfig = reactive({
+      data: [
+        ['测点6', '318℃', '严重报警'],
+        ['测点43', '142℃', '一般预警'],
+        ['测点23', '167℃', '一版预警'],
+        ['测点6', '198℃', '超高预警'],
+        ['测点65', '197℃', '超高预警'],
+        ['测点78', '154℃', '一般预警'],
+        ['测点61', '104℃', '一般预警'],
+        ['测点87', '150℃', '一般信息'],
+      ],
+      index: false,
+      columnWidth: [150],
+      oddRowBGC: '#009acd10',
+      evenRowBGC: '#009acd05',
+      align: ['center', 'center', 'center'],
+    });
+    
+    const [register, { setModalProps }] = useModalInner();
+
+    function handleVisibleChange(visible) {
+      if (visible) {
+        loading.value = true;
+        setModalProps({ loading: true, confirmLoading: true });
+
+        setTimeout(() => {
+          loading.value = false;
+          setModalProps({ loading: false, confirmLoading: false });
+        }, 1000);
+      }
+    }
+
+    // 选择监测
+    function selectDevice (id){
+      loading.value = true;
+      setModalProps({ loading: true, confirmLoading: true });
+       setTimeout(() => {
+        loading.value = false;
+        activeDeviceID.value = id
+        setModalProps({ loading: false, confirmLoading: false });
+      }, 300);
+    }
+
+    watch([() => props.dataSource, () => props.activeID], ([newDataSource, newActiveID], [oldDataSource, oldActiveID]) => {
+      deviceList.value = newDataSource as any[]
+      if(newActiveID != oldActiveID){
+        activeDeviceID.value = newActiveID as string
+      }
+      newDataSource?.forEach((item:any, index) => {
+        if((!activeDeviceID.value && index == 0) || item.deviceID === activeDeviceID.value){
+          activeDeviceID.value = item.deviceID
+          // const list = JSON.parse(item.readData.fibreTemperature)
+          // if(list.length > 0) posList.value = list
+          dustMonitor.value = item.readData
+        }
+      })
+    })
+
+    return { register, model: modelRef, currentTime, handleVisibleChange, selectDevice, deviceList, activeDeviceID, dustMonitor, echatsOption, posList, chartsColumns, columns, warningConfig };
+  },
+  
+});
+</script>
+<style lang="less" scoped>
+  .fiber-modal{
+    width: 100%;
+    height: 650px;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    
+    .modal-left{
+      width: 200px;
+      height: 100%;
+      overflow-y: auto;
+      background: #ffffff11;
+      padding: 5px;
+      border-radius: 5px;
+      .active-device-title {
+        color: aqua;
+      }
+      .link-item{
+        position: relative;
+        cursor: pointer;
+        line-height: 30px;
+        padding-left: 30px;
+        span:hover{
+          color: #89ffff;
+        }
+        &::after{
+          content: '';
+          position: absolute;
+          display: block;
+          width: 8px;
+          height: 8px;
+          top: 12px;
+          left: 10px;
+          transform: rotateZ(45deg) skew(10deg, 10deg);
+          background: #45d3fd;
+        }
+      }
+    }
+    .modal-right{
+      width: calc(100% - 220px);
+      .base-title{
+        line-height: 32px;
+        position: relative;
+        padding-left: 20px;
+        &::after{
+          content: '';
+          position: absolute;
+          display: block;
+          width: 4px;
+          height: 12px;
+          top: 4px;
+          left: 10px;
+          background: #45d3fd;
+          border-radius: 4px;
+        }
+      }
+      .right-top{
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        margin-bottom: 10px;
+        .top-item{
+          width: 200px;
+          height: 80px;
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          border: 1px solid rgba(25,237,255,.4);
+          box-shadow: inset 0 0 10px rgba(0,197,255,.6);
+          background: rgba(0,0,0,.06666666666666667);
+          padding-top: 16px;
+          .icon{
+            margin-right: 10px;
+            margin-top: 5px;
+            color: #FDB146;
+          }
+          .item-container{
+            width: 100px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            div{
+              text-align: center;
+            }
+            .title{
+              font-size: 18px;
+            }
+            .value{
+              text-shadow: 0 0 25px #00fbfe;
+              background: linear-gradient( 0deg,#45d3fd, #45d3fd, #61ddb1,#61ddb1);
+              font-style: normal;
+              background-size: cover;
+              font-family: electronicFont;
+              font-size: 30px;
+              -webkit-background-clip: text;
+              background-clip: text;
+              -webkit-text-fill-color: transparent;
+              position: relative;
+              top: -8px;
+              span{
+                font-family: Arial, Helvetica, sans-serif;
+                font-size: 18px;
+                color: aliceblue;
+              }
+              
+            }
+            
+          }
+        }
+        .warning-box{
+          padding-top: 0px;
+          .icon{
+            margin-top: 20px;
+            .icon-style{
+              color: #FDB146;
+            }
+          }
+          .warning-value{
+            font-size: 18px;
+            color: #61ddb1;
+          }
+        }
+      }
+      .right-center{
+        margin-top: 20px;
+        .dust-group{
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          .dust-item{
+            width: 238px;
+            height: 148px;
+            background: url('/@/assets/images/vent/model_image/dust-bg.png');
+          }
+        }
+      }
+      .right-bottom{
+        margin-top: 20px;
+        .echarts-box{
+          width: 100%;
+          height: 230px;
+        }
+      }
+
+      
+    }
+  }
+</style>

+ 416 - 0
src/views/vent/monitorManager/deviceMonitor/modal/fiber.modal.vue

@@ -0,0 +1,416 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="register" :title="`光纤测温详情    ${currentTime}`" width="1200px" @ok="handleOk" @cancel="handleCancel" >
+    <div class="fiber-modal">
+      <div class="modal-left">
+        <div v-for="device in deviceList" class="link-item" :class="{'active-device-title': device.deviceID === activeDeviceID }" :key="device.deviceID">
+          <span class="" @click="selectDevice(device.deviceID)">{{ device.stationname }}</span>
+        </div>
+      </div>
+      <div class="modal-right">
+        <div class="right-top">
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style max-temperature" size="38" name="max-temperature.svg" />
+            </div>
+            <div class="item-container">
+              <div class="title">最高温度</div>
+              <div class="value">{{ posMonitor.fmax }} <span>℃</span> </div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style min-temperature" size="38" name="min-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">最低温度</div>
+              <div class="value">{{ posMonitor.fmin }} <span>℃</span></div>
+            </div>
+          </div>
+          <div class="top-item">
+            <div class="icon">
+              <SvgIcon class="icon-style aveg-temperature" size="38" name="aveg-temperature" />
+            </div>
+            <div class="item-container">
+              <div class="title">平均温度</div>
+              <div class="value">{{ posMonitor.favg }} <span>℃</span></div>
+            </div>
+          </div>
+          <div class="top-item warning-box">
+            <div class="icon">
+              <SvgIcon class="icon-style" size="38" name="risk-level" />
+            </div>
+            <div class="item-container">
+              <div class="title">风险等级</div>
+              <div class="warning-value">低风险</div>
+            </div>
+          </div>
+        </div>
+        <div class="right-center">
+          <div class="table-box">
+            <span class="base-title">测点监测详情</span>
+            <a-table
+              size="small"
+              :columns="columns"
+              :data-source="posList"
+              :pagination="false"
+              :scroll="{ y: 200 }"
+            />
+          </div>
+          <div class="warning-box">
+            <span class="base-title">预警历史详情</span>
+            <div class="warning-container">
+              <dv-scroll-board ref="scrollBoard" :config="warningConfig" style="width: 100%; height: 240px; overflow-y: auto; border: 1px solid #39e8ff33;" />
+            </div>
+          </div>
+        </div>
+        <div class="right-bottom">
+          <span class="base-title">测点监测曲线</span>
+          <div class="echarts-box">
+            <BarAndLine
+              xAxisPropType="pos"
+              :dataSource="posList"
+              height="100%"
+              :chartsColumns="chartsColumns"
+              :option="echatsOption"
+              chartsType="listMonitor" />
+          </div>
+        </div>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+import { defineComponent, ref, watch, shallowRef, reactive } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import BarAndLine from '/@/components/chart/BarAndLine.vue';
+import { SvgIcon } from '/@/components/Icon';
+import { Decoration7 as DvDecoration7, ScrollBoard as DvScrollBoard } from '@kjgl77/datav-vue3';
+import dayjs from 'dayjs'
+
+export default defineComponent({
+  components: { BasicModal, BarAndLine, SvgIcon, DvScrollBoard, DvDecoration7 },
+  props: {
+    dataSource: {type: Array},
+    activeID: {type: String}
+  },
+  setup(props) {
+    const currentTime = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))
+    const modelRef = ref({});
+    const loading = ref(true);
+    const activeDeviceID = ref('');
+    const deviceList = ref<any[]>([])
+    const posList = ref<any[]>([])
+    const posMonitor = shallowRef({})
+
+    const echatsOption = {
+      grid: {
+        top: '20%',
+        left: '2px',
+        right: '10px',
+        bottom: '3%',
+        containLabel: true
+      },
+      toolbox: {
+        feature: {}
+      }
+    }
+
+    const chartsColumns = [
+      {
+        legend: '测点温度',
+        seriesName: '(℃)',
+        ymax: 200,
+        yname: '℃',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#FDB146',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'value',
+      },
+    ]
+
+    const columns = [
+      {
+        title: '安装位置',
+        dataIndex: 'position',
+        width: 60,
+        align: 'center',
+        customRender: ({ index }) => {
+          return `测点${index}`
+        }
+      },
+      {
+        title: '安装距离(m)',
+        dataIndex: 'pos',
+        align: 'center',
+        width: 60,
+      },
+      {
+        title: '测点温度',
+        dataIndex: 'value',
+        align: 'center',
+        width: 50,
+      },
+      {
+        title: '测点状态',
+        dataIndex: 'state',
+        align: 'center',
+        width: 50,
+        customRender: () => {
+          return `正常`
+        }
+      },
+    ];
+
+    const warningConfig = reactive({
+      header: ['测点', '温度', '预警信息'],
+      data: [
+        ['测点6', '318℃', '严重报警'],
+        ['测点43', '142℃', '一般预警'],
+        ['测点23', '167℃', '一版预警'],
+        ['测点6', '198℃', '超高预警'],
+        ['测点65', '197℃', '超高预警'],
+        ['测点78', '154℃', '一般预警'],
+        ['测点61', '104℃', '一般预警'],
+        ['测点87', '150℃', '一般信息'],
+      ],
+      index: false,
+      columnWidth: [150],
+      headerHeight: 38,
+      headerBGC: '#3d9dd45d',
+      oddRowBGC: '#009acd10',
+      evenRowBGC: '#009acd05',
+      align: ['center', 'center', 'center'],
+    });
+    
+    const [register, { setModalProps, closeModal }] = useModalInner();
+
+    function handleVisibleChange(visible) {
+      if (visible) {
+        loading.value = true;
+        setModalProps({ loading: true, confirmLoading: true });
+
+        setTimeout(() => {
+          loading.value = false;
+          setModalProps({ loading: false, confirmLoading: false });
+        }, 1000);
+      }
+    }
+
+    // 选择监测
+    function selectDevice (id){
+      loading.value = true;
+      setModalProps({ loading: true, confirmLoading: true });
+       setTimeout(() => {
+        loading.value = false;
+        activeDeviceID.value = id
+        setModalProps({ loading: false, confirmLoading: false });
+      }, 300);
+    }
+
+    function handleOk(e) {
+      e.preventDefault()
+      closeModal()
+    }
+
+    function handleCancel(e) {
+      e.preventDefault()
+      closeModal()
+    }
+
+    watch([() => props.dataSource, () => props.activeID], ([newDataSource, newActiveID], [oldDataSource, oldActiveID]) => {
+      deviceList.value = newDataSource as any[]
+      if(newActiveID != oldActiveID){
+        activeDeviceID.value = newActiveID as string
+      }
+      newDataSource?.forEach((item:any, index) => {
+        if((!activeDeviceID.value && index == 0) || item.deviceID === activeDeviceID.value){
+          activeDeviceID.value = item.deviceID
+          const list = JSON.parse(item.readData.fibreTemperature)
+          if(list.length > 0) posList.value = list
+          posMonitor.value = item.readData
+        }
+      })
+    })
+
+    return { register, model: modelRef, currentTime, handleVisibleChange, selectDevice, handleOk, handleCancel, deviceList, activeDeviceID, posMonitor, echatsOption, posList, chartsColumns, columns, warningConfig };
+  },
+  
+});
+</script>
+<style lang="less" scoped>
+  .fiber-modal{
+    width: 100%;
+    height: 650px;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    
+    .modal-left{
+      width: 200px;
+      height: 100%;
+      overflow-y: auto;
+      background: #ffffff11;
+      padding: 5px;
+      border-radius: 5px;
+      .active-device-title {
+        color: aqua;
+      }
+      .link-item{
+        position: relative;
+        cursor: pointer;
+        line-height: 30px;
+        padding-left: 30px;
+        span:hover{
+          color: #89ffff;
+        }
+        &::after{
+          content: '';
+          position: absolute;
+          display: block;
+          width: 8px;
+          height: 8px;
+          top: 12px;
+          left: 10px;
+          transform: rotateZ(45deg) skew(10deg, 10deg);
+          background: #45d3fd;
+        }
+      }
+    }
+    .modal-right{
+      width: calc(100% - 220px);
+      .base-title{
+        line-height: 32px;
+        position: relative;
+        padding-left: 20px;
+        &::after{
+          content: '';
+          position: absolute;
+          display: block;
+          width: 4px;
+          height: 12px;
+          top: 4px;
+          left: 10px;
+          background: #45d3fd;
+          border-radius: 4px;
+        }
+      }
+      .right-top{
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        margin-bottom: 10px;
+        .top-item{
+          width: 200px;
+          height: 80px;
+          display: flex;
+          flex-direction: row;
+          justify-content: center;
+          border: 1px solid rgba(25,237,255,.4);
+          box-shadow: inset 0 0 10px rgba(0,197,255,.6);
+          background: rgba(0,0,0,.06666666666666667);
+          padding-top: 16px;
+          .icon{
+            margin-right: 10px;
+            margin-top: 5px;
+            color: #FDB146;
+          }
+          .item-container{
+            width: 100px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            div{
+              text-align: center;
+            }
+            .title{
+              font-size: 18px;
+            }
+            .value{
+              text-shadow: 0 0 25px #00fbfe;
+              background: linear-gradient( 0deg,#45d3fd, #45d3fd, #61ddb1,#61ddb1);
+              font-style: normal;
+              background-size: cover;
+              font-family: electronicFont;
+              font-size: 30px;
+              -webkit-background-clip: text;
+              background-clip: text;
+              -webkit-text-fill-color: transparent;
+              position: relative;
+              top: -8px;
+              span{
+                font-family: Arial, Helvetica, sans-serif;
+                font-size: 18px;
+                color: aliceblue;
+              }
+              
+            }
+            
+          }
+        }
+        .warning-box{
+          padding-top: 0px;
+          .icon{
+            margin-top: 20px;
+            .icon-style{
+              color: #FDB146;
+            }
+          }
+          .warning-value{
+            font-size: 18px;
+            color: #61ddb1;
+          }
+        }
+      }
+      .right-center{
+        margin-top: 20px;
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        .table-box{
+          position: relative;
+          width: 500px;
+          height: 250px;
+        }
+        .warning-box{
+          width: calc(100% - 520px);
+          .warning-container{
+            width: 100%;
+            height: convert;
+            background: #009acd00;
+            :deep(.dv-scroll-board){
+              .row-item{
+                height: 40px !important;
+                line-height: 40px !important;
+              }
+              .header-item{
+                border-top: 1px solid #91e9fe !important;
+                border-bottom: 1px solid #91e9fe !important;
+              }
+            }
+
+          }
+        }
+      }
+      .right-bottom{
+        margin-top: 20px;
+        .echarts-box{
+          width: 100%;
+          height: 230px;
+        }
+      }
+
+      
+    }
+  }
+  :deep(.zxm-table-body){
+    border: 1px solid rgba(57, 232, 255, 0.2) !important;
+    .zxm-table-tbody > tr > td{
+      border: none !important;
+    }
+  }
+  :deep(.zxm-table-cell){
+    border-right: none !important;
+  }
+</style>

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

@@ -101,7 +101,7 @@
         </a-tab-pane>
         <a-tab-pane key="5" tab="操作历史">
           <div class="tab-item">
-            <HandlerHistoryTable columns-type="alarm_history" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
+            <HandlerHistoryTable columns-type="operatorhistory" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
           </div>
         </a-tab-pane>
       </a-tabs>
@@ -328,15 +328,13 @@
 
   //
   async function getDataSource(){
-    const res = await list({ devicetype: 'fan', pagetype: 'normal' });
+    const res = await list({ devicetype: 'fanlocal', pagetype: 'normal' });
     const dataArr = res.msgTxt[0].datalist || [];
     dataSource.value = [];
     dataArr.forEach((data) => {
-      if (data.deviceType?.startsWith('fanlocal')) {
-        const readData = data.readData;
-        data = Object.assign(data, readData);
-        dataSource.value.push(data);
-      }
+      const readData = data.readData;
+      data = Object.assign(data, readData);
+      dataSource.value.push(data);
     });
     const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
     return data;

+ 0 - 15
src/views/vent/monitorManager/fiberMonitor/fiber.belt.threejs.ts

@@ -360,21 +360,6 @@ class beltFiber {
         // this.addBeltText();
         resolve(null);
       });
-
-      // window.onresize = function () {
-      //   const width = window.innerWidth;
-      //   const height = window.innerHeight;
-
-      //   model.camera.aspect = width / height;
-      //   model.camera.updateProjectionMatrix();
-
-      //   model.renderer.setSize(width, height);
-
-      //   bloomComposer.setSize(width, height);
-      //   finalComposer.setSize(width, height);
-
-      //   render();
-      // };
     });
   }
 

+ 15 - 27
src/views/vent/monitorManager/fiberMonitor/fiber.data.ts

@@ -411,51 +411,39 @@ export const formAgentSchema: FormSchema[] = [
 
 export const chartsColumns = [
   {
-    legend: 'V1风速',
-    seriesName: '(m/min)',
-    ymax: 20,
-    yname: 'm/min',
+    legend: '平均温度',
+    seriesName: '',
+    ymax: '100',
+    yname: '',
     linetype: 'bar',
     yaxispos: 'left',
     color: '#cd5fff',
     sort: 1,
     xRotate: 0,
-    dataIndex: 'incipientWindSpeed1',
+    dataIndex: 'favg',
   },
   {
-    legend: 'V2风速',
+    legend: '最高温度',
     seriesName: '',
-    ymax: 20,
-    yname: 'm/min',
-    linetype: 'bar',
+    ymax: '100',
+    yname: '',
+    linetype: 'line',
     yaxispos: 'left',
     color: '#3DF6FF',
     sort: 1,
     xRotate: 0,
-    dataIndex: 'incipientWindSpeed2',
+    dataIndex: 'fmax',
   },
   {
-    legend: 'V3风速',
+    legend: '最低温度',
     seriesName: '',
-    ymax: 20,
-    yname: 'm/min',
-    linetype: 'bar',
+    ymax: '100',
+    yname: '',
+    linetype: 'line',
     yaxispos: 'left',
     color: '#fac858',
     sort: 1,
     xRotate: 0,
-    dataIndex: 'incipientWindSpeed3',
-  },
-  {
-    legend: '气源压力',
-    seriesName: '(MPa)',
-    ymax: 50,
-    yname: 'MPa',
-    linetype: 'line',
-    yaxispos: 'right',
-    color: '#fc8452',
-    sort: 2,
-    xRotate: 0,
-    dataIndex: 'sourcePressure',
+    dataIndex: 'fmin',
   },
 ];

+ 3 - 3
src/views/vent/monitorManager/fiberMonitor/fiber.workFace.threejs.ts

@@ -7,9 +7,9 @@ import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader.js';
 import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js';
 import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader.js';
 import { CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
-import * as dat from 'dat.gui';
-const gui = new dat.GUI();
-gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
 
 class WorkFace {
   model;

+ 16 - 12
src/views/vent/monitorManager/fiberMonitor/index.vue

@@ -48,8 +48,8 @@
     <div class="bottom-tabs-box">
       <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
         <a-tab-pane key="1" tab="实时监测">
-          <MonitorTable columnsType="window_monitor"  :dataSource="dataSource" @selectRow="getSelectRow"
-            design-scope="window-monitor" title="风窗监测">
+          <MonitorTable columnsType="fiber_monitor"  :dataSource="dataSource" @selectRow="getSelectRow"
+            design-scope="fiber-monitor" title="皮带机监测">
             <template #filterCell="{ column, record }">
               <a-tag v-if="column.dataIndex === 'warnFlag'" :color="record.warnFlag == 0 ? 'green' : 'red'">{{
                 record.warnFlag == 0 ? '正常' : '报警'
@@ -63,25 +63,25 @@
         </a-tab-pane>
         <a-tab-pane key="2" tab="实时曲线图" force-render>
           <div class="tab-item" v-if="activeKey === '2'">
-            <DeviceEcharts chartsColumnsType="window_chart" xAxisPropType="strname" :dataSource="dataSource" height="100%"
-              :chartsColumns="chartsColumns" :device-list-api="baseList" device-type="window" />
+            <DeviceEcharts chartsColumnsType="fiber_chart" xAxisPropType="strname" :dataSource="dataSource" height="100%"
+              :chartsColumns="chartsColumns" :device-list-api="baseList" device-type="fiber" />
           </div>
         </a-tab-pane>
         <a-tab-pane key="3" tab="历史数据">
           <div class="tab-item">
-            <HistoryTable columns-type="window_history" device-type="window" :device-list-api="baseList"
-              designScope="window-history" />
+            <HistoryTable columns-type="fibre_history" device-type="fiber" :device-list-api="baseList"
+              designScope="fiber-history" />
           </div>
         </a-tab-pane>
         <a-tab-pane key="4" tab="报警历史">
           <div class="tab-item">
-            <AlarmHistoryTable columns-type="alarm_history" device-type="window" :device-list-api="baseList"
+            <AlarmHistoryTable columns-type="alarm_history" device-type="fiber" :device-list-api="baseList"
               designScope="alarm-history" />
           </div>
         </a-tab-pane>
         <a-tab-pane key="5" tab="操作历史">
           <div class="tab-item">
-            <HandlerHistoryTable columns-type="alarm_history" device-type="fanlocal" :device-list-api="baseList"
+            <HandlerHistoryTable columns-type="operatorhistory" device-type="fiber" :device-list-api="baseList"
               designScope="alarm-history" />
           </div>
         </a-tab-pane>
@@ -174,7 +174,10 @@ function getMonitor(){
 };
 
 async function getDataSource(){
-  const res = await list({ devicetype: 'window', pagetype: 'normal' });
+  console.log(11111)
+  const res = await list({ devicetype: 'fiber', pagetype: 'normal' });
+  console.log(2222, res)
+
   dataSource.value = res.msgTxt[0].datalist || [];
   dataSource.value.forEach((data: any) => {
     const readData = data.readData;
@@ -193,6 +196,7 @@ function getDeviceBaseList(){
 
 // 切换检测数据
 function getSelectRow(selectRow, index){
+  
   if (!selectRow) return;
   selectRowIndex.value = index;
   const baseData: any = deviceBaseList.value.find((baseData: any) => baseData.id === selectRow.deviceID);
@@ -207,16 +211,16 @@ onBeforeMount(() => {
 
 onMounted(() => {
   loading.value = true;
+  
   mountedThree().then(async () => {
     loading.value = false;
-    getMonitor();
-
+    // getMonitor();
     setTimeout(() => {
       warningNum.value = [3, 6]
       errorNum.value = [9]
     }, 3000)
-
   });
+  getMonitor();
 });
 
 onUnmounted(() => {

+ 1 - 1
src/views/vent/monitorManager/gateMonitor/gate.api.ts

@@ -2,7 +2,7 @@ import { defHttp } from '/@/utils/http/axios';
 import { Modal } from 'ant-design-vue';
 
 enum Api {
-  list = '/monitor/device',
+  list = '/ventanaly-device/monitor/device',
   save = '/safety/ventanalyGate/add',
   edit = '/safety/ventanalyGate/edit',
   deleteById = '/safety/ventanalyGate/delete',

+ 3 - 3
src/views/vent/monitorManager/gateMonitor/index.vue

@@ -126,17 +126,17 @@
         </a-tab-pane>
         <a-tab-pane key="3" tab="历史数据">
           <div class="tab-item">
-            <HistoryTable columns-type="gate_history" device-type="gate" :device-list-api="baseList" designScope="gate-history" />
+            <HistoryTable columns-type="gate_history" device-type="gate" :device-list-api="getTableList" designScope="gate-history" />
           </div>
         </a-tab-pane>
         <a-tab-pane key="4" tab="报警历史">
           <div class="tab-item">
-            <AlarmHistoryTable columns-type="alarm_history" device-type="gate" :device-list-api="baseList" designScope="alarm-history" />
+            <AlarmHistoryTable columns-type="alarm_history" device-type="gate" :device-list-api="getTableList" designScope="alarm-history" />
           </div>
         </a-tab-pane>
         <a-tab-pane key="5" tab="操作历史">
           <div class="tab-item">
-            <HandlerHistoryTable columns-type="alarm_history" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
+            <HandlerHistoryTable columns-type="operatorhistory" device-type="gate" :device-list-api="getTableList" designScope="alarm-history" />
           </div>
         </a-tab-pane>
       </a-tabs>

+ 6 - 8
src/views/vent/monitorManager/mainFanMonitor/index.vue

@@ -174,7 +174,7 @@
         </a-tab-pane>
         <a-tab-pane key="5" tab="操作历史">
           <div class="tab-item">
-            <HandlerHistoryTable columns-type="alarm_history" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
+            <HandlerHistoryTable columns-type="operatorhistory" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
           </div>
         </a-tab-pane>
       </a-tabs>
@@ -232,7 +232,7 @@
   import { deviceControlApi } from '/@/api/vent/index';
   import { mountedThree, destroy, addText, play, setModelType, playAnimate, resetEcharts } from './main.threejs';
   import LivePlayer from '@liveqing/liveplayer-v3';
-  import { Icon as SvgIcon  } from '/@/components/Icon';
+  import { SvgIcon } from '/@/components/Icon';
   import { list, pathList, deviceList, testWind } from './main.api';
   import { list as baseList } from '../../deviceManager/fanTabel/fan.api';
   import { getTableList } from '/@/views/vent/monitorManager/fanLocalMonitor/fanLocal.api';
@@ -318,15 +318,13 @@
   const controlType = ref(1);
 
   const getDataSource = async () => {
-    const res = await list({ devicetype: 'fan', pagetype: 'normal' });
+    const res = await list({ devicetype: 'fanmain', pagetype: 'normal' });
     const dataArr = res.msgTxt[0].datalist || [];
     dataSource.value = [];
     dataArr.forEach((data) => {
-      if (data.deviceType?.startsWith('fanmain')) {
-        const readData = data.readData;
-        data = Object.assign(data, readData);
-        dataSource.value.push(data);
-      }
+      const readData = data.readData;
+      data = Object.assign(data, readData);
+      dataSource.value.push(data);
     });
     const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
     return data;

+ 87 - 0
src/views/vent/monitorManager/nitrogen/components/bottomMenu.vue

@@ -0,0 +1,87 @@
+<template>
+  <div class="bottom-btn-group">
+    <div v-for="item in navList" :key="item.pathName" class="vent-row-center btn-item" @click="setBtn('click', item)"
+      @mouseenter="setBtn('over', item)" @mouseleave="setBtn('leave', item)">
+      <dv-decoration11
+        :color="isBtnActive === item.pathName ? activeColors : item.isHover ? activeColors : noActiveColors"
+        style="width:200px;height:60px;">
+        {{ item.title }}
+      </dv-decoration11>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
+import { Decoration5, Decoration11 as DvDecoration11} from '@kjgl77/datav-vue3'
+
+const router = useRouter()
+const isBtnActive = ref('nitrogen_page_lh')
+const activeColors = ['#009BFF', '#28DBE4']
+const noActiveColors = ['#aaa', '#aaa']
+const navList = ref([
+  {
+    title: '监控界面',
+    pathName: 'nitrogen_page_lh',
+    isHover: true
+  },
+  {
+    title: '关键节点监测',
+    pathName: 'critical_node',
+    isHover: false
+  },
+  {
+    title: '实时曲线',
+    pathName: 'yfj_monitor_echarts',
+    isHover: false
+  },
+  {
+    title: '压风机历史记录',
+    pathName: 'yfj_history',
+    isHover: false
+  },
+  {
+    title: '操作历史记录',
+    pathName: 'yfj_handler_history',
+    isHover: false
+  },
+  {
+    title: '故障诊断历史记录',
+    pathName: 'yfj_faultRecord',
+    isHover: false
+  }
+])
+
+
+function setBtn(type, activeObj) {
+  if (type === 'over') {
+    activeObj.isHover = true
+  } else if (type === 'leave') {
+    activeObj.isHover = false
+  } else if (type === 'click') {
+    isBtnActive.value = activeObj.pathName
+  }
+  // router.push('')
+}
+
+</script>
+<style lang="less" scoped>
+.bottom-btn-group {
+    display: flex;
+    position: fixed;
+    width: calc(100% - 400px);
+    height: 100px;
+    bottom: 20px;
+    align-items: center;
+    justify-content: center;
+
+    .btn-item {
+      width: 200px;
+      height: 60px;
+      margin: 10px;
+      color: #fff;
+      cursor: pointer;
+      pointer-events: auto;
+    }
+  }
+</style>

+ 17 - 0
src/views/vent/monitorManager/nitrogen/components/nitrogenAlarmHistory.vue

@@ -0,0 +1,17 @@
+<template>
+  <div class="alarm-history">
+     <AlarmHistoryTable columns-type="alarm_history" device-type="pressurefan" :device-list-api="getTableList.bind(null, { devicekind: 'pressurefan' })" designScope="alarm-history" />
+  </div>
+</template>
+<script setup lang="ts">
+  import AlarmHistoryTable from '../../comment/AlarmHistoryTable.vue';
+  import { getTableList } from '../nitrogen.api'
+
+</script>
+<style lang="less" scoped>
+  .alarm-history{
+    width: 100%;
+    position: fixed;
+    top: 80px;
+  }
+</style>

+ 246 - 0
src/views/vent/monitorManager/nitrogen/components/nitrogenEcharts.vue

@@ -0,0 +1,246 @@
+<template>
+  <div class="nitrogen-echatrs-box">  
+    <div class="button-box">
+      <div style="color: #fff; font-weight: 600;">{{ currentTime }}</div>
+    </div>
+    <div class="echarts-container">
+      <div v-for="(item, index) in dataSource" :key="index" class="echarts-item">
+        <div class="echarts-nitrogen-item">
+          <BarAndLine
+          xAxisPropType="readTime"
+          :dataSource="item"
+          height="100%"
+          :chartsColumns="nitrogenChartsColumns"
+          :option="nitrogenOption"
+          chartsType="detail" />
+        </div>
+        <div class="echarts-cqg-item">
+          <BarAndLine
+            xAxisPropType="readTime"
+            :dataSource="item"
+            height="100%"
+            :chartsColumns="cqgChartsColumns"
+            :option="cqgOption"
+            chartsType="detail" />
+        </div>
+      </div>    
+    </div>
+    </div>
+  </template>
+  <script setup lang="ts">
+    import{ref, onMounted, onUnmounted, reactive } from 'vue'
+    import dayjs from 'dayjs'
+    import BarAndLine from '/@/components/chart/BarAndLine.vue';
+    import { list } from '../nitrogen.api'
+
+    const nitrogenChartsColumns = [
+      {
+        legend: '空压机排气压力',
+        seriesName: '(Mpa)',
+        ymax: 100,
+        yname: 'Pa',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#9BCB75',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'compressExhaustPressF1',
+      },
+      {
+        legend: '空压机分离压力',
+        seriesName: '(Mpa)',
+        ymax: 100,
+        yname: 'Mpa',
+        linetype: 'line',
+        yaxispos: 'left',
+        color: '#1EB0FC',
+        sort: 1,
+        xRotate: 0,
+        dataIndex: 'compressSeparatePressF1',
+      },
+      {
+        legend: '空压机主机温度',
+        seriesName: '(℃)',
+        ymax: 200,
+        yname: '℃',
+        linetype: 'line',
+        yaxispos: 'right',
+        color: '#FDB146',
+        sort: 2,
+        xRotate: 0,
+        dataIndex: 'compressHostTempF1',
+      },
+      {
+        legend: '空压机机组温度',
+        seriesName: '(℃)',
+        ymax: 200,
+        yname: '℃',
+        linetype: 'line',
+        yaxispos: 'right',
+        color: '#EE6666',
+        sort: 2,
+        xRotate: 0,
+        dataIndex: 'compressCrewTempF1',
+      },
+    ];
+    const cqgChartsColumns = [
+    {
+      legend: '储气罐压力',
+      seriesName: '(Mpa)',
+      ymax: 100,
+      yname: 'Pa',
+      linetype: 'line',
+      yaxispos: 'left',
+      color: '#9BCB75',
+      sort: 1,
+      xRotate: 0,
+      dataIndex: 'airReceiverPress',
+    },
+    {
+      legend: '储气罐温度',
+      seriesName: '(℃)',
+      ymax: 100,
+      yname: '℃',
+      linetype: 'line',
+      yaxispos: 'right',
+      color: '#DD7FCD',
+      sort: 2,
+      xRotate: 0,
+      dataIndex: 'airReceiverTemp',
+    },
+    {
+      legend: '储气罐流量',
+      seriesName: '(m³/k)',
+      ymax: 200,
+      yname: 'm³/k',
+      linetype: 'line',
+      yaxispos: 'right',
+      color: '#56B1FD',
+      sort: 3,
+      xRotate: 0,
+      dataIndex: 'airReceiverFlow',
+    },
+  ];
+
+    const nitrogenOption = {
+      grid: {
+        top: '20%',
+        left: '2px',
+        right: '0px',
+        bottom: '3%',
+        containLabel: true
+      },
+      toolbox: {
+        feature:{
+          
+        }
+      }
+    }
+
+    const cqgOption = {
+      grid: {
+        top: '20%',
+        left: '0px',
+        right: '40px',
+        bottom: '3%',
+        containLabel: true
+      },
+      toolbox: {
+        feature: {
+
+        }
+      }
+    }
+
+    const currentTime = ref(dayjs().format('YYYY-MM-DD HH:mm:ss'))
+    // const monitorData = [] as any[]
+    const dataSource = reactive<any[]>([])
+
+    // https获取监测数据
+    let timer: null | NodeJS.Timeout = null;
+    let count = 0
+    async function getMonitor() {
+      if (Object.prototype.toString.call(timer) === '[object Null]') {
+        timer = await setTimeout(async () => {
+          await getDataSource();
+          if (timer) {
+            timer = null;
+          }
+          await getMonitor();
+        }, 1000);
+      }
+    };
+
+    async function getDataSource() {
+      
+      const res = await list({ devicetype: 'pressurefan', pagetype: 'normal' });
+      const dataList = res.msgTxt[0].datalist || [];
+      dataList.forEach((data, index) => {
+        const item = data.readData;
+        Object.assign(item, data);
+        item['readTime'] = item['readTime'].substring(11)
+        if(count == 0){
+          dataSource.push([item])
+        }else {
+          if(dataSource[index].length < 10){
+            dataSource[index].push(item)
+          }else {
+            dataSource[index].shift()
+            dataSource[index].push(item)
+          }
+        }
+      });
+      count++ // 实时数据累计
+      console.log('实时监测数据----->', dataSource)
+    };
+
+    onMounted(() => {
+      getMonitor()
+    })
+
+    onUnmounted(() => {
+      if (timer) {
+        clearTimeout(timer);
+        timer = undefined;
+      }
+    });
+
+</script>
+<style lang="less" scoped>
+  .button-box{
+    text-align: end;
+    margin-top: 10px;
+    margin-right: 10px;
+  }
+  .nitrogen-echatrs-box{
+    width: 100%;
+    height: 100%;
+  }
+  .echarts-container{
+    position: fixed;
+    width: 100%;
+    height: 730px;
+    color: #fff;
+    overflow: scroll;
+    top: 100px;
+    display: flex;
+    flex-direction: column;
+    z-index: 99999;
+    
+    .echarts-item{
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      .echarts-nitrogen-item{
+        width: calc(60% - 30px);
+        height: 240px;
+      }
+      .echarts-cqg-item{
+        width: calc(40% - 10px);
+        height: 240px;
+      }
+    }
+    
+  }
+
+</style>

+ 16 - 0
src/views/vent/monitorManager/nitrogen/components/nitrogenHandleHistory.vue

@@ -0,0 +1,16 @@
+<template>
+  <div class="handle-history">
+     <HandlerHistoryTable columns-type="operatorhistory" device-type="pressurefan" :device-list-api="getTableList.bind(null, {devicekind :'pressurefan'})" designScope="pressurefan_history" />
+  </div>
+</template>
+<script setup lang="ts">
+  import HandlerHistoryTable from '../../comment/HandlerHistoryTable.vue';
+  import { getTableList } from '../nitrogen.api'
+
+</script>
+<style lang="less" scoped>
+  .handle-history{
+    position: fixed;
+    top: 80px;
+  }
+</style>

+ 16 - 0
src/views/vent/monitorManager/nitrogen/components/nitrogenHistory.vue

@@ -0,0 +1,16 @@
+<template>
+  <div class="nitrogen-history">
+     <HistoryTable columns-type="pressurefan_history" device-type="pressurefan" :device-list-api="getTableList.bind(null, {devicekind :'pressurefan'})" designScope="pressurefan_history" />
+  </div>
+</template>
+<script setup lang="ts">
+  import HistoryTable from '../../comment/HistoryTable.vue';
+  import { getTableList } from '../nitrogen.api'
+
+</script>
+<style lang="less" scoped>
+  .nitrogen-history{
+    position: fixed;
+    top: 80px;
+  }
+</style>

+ 615 - 0
src/views/vent/monitorManager/nitrogen/components/nitrogenHome.vue

@@ -0,0 +1,615 @@
+<template>
+    <div id="nitrogenCss3D" class="threejs-Object-CSS"
+      style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 2; top: 0px; left: 0px">
+      <a-spin :spinning="loading" />
+      <div v-for="groupNum in monitorDataGroupNum" :key="groupNum" class="modal-monitor">
+        <fourBorderBg :class="`kyj${groupNum}`" :id="`nitrogenMonitor${groupNum}`">
+          <div class="title">{{ groupNum }}号空压机 </div>
+          <div class="monitor-item">
+            <span class="monitor-title">排气压力:</span>
+            <span class="monitor-val"><span class="val">{{ monitorData[groupNum - 1]['compressExhaustPressF1'] ?
+              monitorData[groupNum - 1]['compressExhaustPressF1'] : '-' }}</span><span class="unit">Mpa</span></span>
+          </div>
+          <div class="monitor-item">
+            <span class="monitor-title">分离压力:</span>
+            <span class="monitor-val"><span class="val">{{ monitorData[groupNum - 1]['compressSeparatePressF1'] ?
+              monitorData[groupNum - 1]['compressSeparatePressF1'] : '-' }}</span><span class="unit">Mpa</span></span>
+          </div>
+          <div class="monitor-item">
+            <span class="monitor-title">排气温度:</span>
+            <span class="monitor-val"><span class="val">{{ monitorData[groupNum - 1]['exhaustTemp'] ? monitorData[groupNum
+              - 1]['exhaustTemp'] : '-' }}</span><span class="unit">℃</span></span>
+          </div>
+          <div class="signal-item">
+            <div class="signal"><span class="monitor-title">运行信号</span><span
+                :class="{ 'signal-round': true, 'signal-round-run': monitorData[groupNum - 1]['compressRunSigF1'], 'signal-round-gry': !monitorData[groupNum - 1]['compressRunSigF1'] }"></span>
+            </div>
+            <div class="signal"><span class="monitor-title">加载信号</span><span
+                :class="{ 'signal-round': true, 'signal-round-run': monitorData[groupNum - 1]['compressLoadSigF1'], 'signal-round-gry': !monitorData[groupNum - 1]['compressLoadSigF1'] }"></span>
+            </div>
+          </div>
+        </fourBorderBg>
+        <fourBorderBg :class="`cqg${groupNum}`" :id="`cqgMonitor${groupNum}`">
+          <div class="title">{{ cqgs[groupNum - 1] }}</div>
+          <div class="monitor-item">
+            <span class="monitor-title">气囊温度:</span>
+            <span class="monitor-val"><span class="val">{{ monitorData[groupNum - 1]['airReceiverTemp'] ?
+              monitorData[groupNum - 1]['airReceiverTemp'] : '-' }}</span><span class="unit">℃</span></span>
+          </div>
+          <div class="monitor-item">
+            <span class="monitor-title">气囊压力<span class="unit"></span>:</span>
+            <span class="monitor-val"><span class="val">{{ monitorData[groupNum - 1]['airReceiverPress'] ?
+              monitorData[groupNum - 1]['airReceiverPress'] : '-' }}</span><span class="unit">Mpa</span></span>
+          </div>
+          <div class="monitor-item">
+            <span class="monitor-title">气囊流量<span class="unit"></span>:</span>
+            <span class="monitor-val"><span class="val">{{ monitorData[groupNum - 1]['airReceiverFlow'] ?
+              monitorData[groupNum - 1]['airReceiverFlow'] : '-' }}</span><span class="unit">m³/k</span></span>
+          </div>
+        </fourBorderBg>
+      </div>
+    </div>
+    <div id="nitrogen3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"></div>
+    <div class="nitrogen-home">
+      <div class="nitrogen-container">
+        <div class="top-box">
+          <!-- 左边监测数据 -->
+          <div class="lr-box left-box">
+            <div class="item item-l" v-for="groupNum in monitorDataGroupNum" :key="groupNum">
+              <div class="monitor-box">
+                <!-- <div class="device-title">{{ monitorData[groupNum - 1]['strName'] }}</div>-->
+                <dv-decoration7 style="height:30px;">
+                  <div class="base-title">{{ groupNum }}号空压机组</div>
+                </dv-decoration7>
+                <div class="state-item" v-for="(data, index) in showMonitorData" :key="index">
+                  <div class="item-col">
+                    <span class="state-title">{{ Object.values(data)[0] }} :</span>
+                    <span class="state-val">{{ (monitorData.length > 0 && monitorData[groupNum - 1][Object.keys(data)[0]])
+                      >= 0 ? monitorData[groupNum - 1][Object.keys(data)[0]] : '-' }}</span>
+                  </div>
+                  <div class="item-col">
+                    <span class="state-title">{{ Object.values(data)[1] }} :</span>
+                    <span class="state-val">{{ (monitorData.length > 0 && monitorData[groupNum - 1][Object.keys(data)[1]])
+                      >= 0 ? monitorData[groupNum - 1][Object.keys(data)[1]] : '-' }}</span>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+          <!-- 右边控制状态 -->
+          <div class="lr-box right-box">
+            <div class="item">
+              <div class="control-item">
+                <div class="control-item-l">
+                  <!-- <img src="@/assets/img/yccz.png" alt="" width="36px" height="36px" style="margin-right: 10px;"> -->
+                  <span style="font-size: 18px;">远程控制</span>
+                </div>
+              </div>
+              <div class="control-item" v-for="groupNum in monitorDataGroupNum" :key="groupNum">
+                <div class="control-item-l">
+                  <span class="round"></span>
+                  <span>{{ kyjs[groupNum - 1] }}</span>
+                </div>
+                <div class="control-item-r" style="display: flex; align-items: center;">
+                  <a-switch v-model="airCompressorState[groupNum - 1][`compressRunSigF1`]" checked-children="开启"
+                    un-checked-children="关闭" :disabled="airCompressorState[groupNum - 1][`controlModel`]"
+                    @change="handlerDevice(airCompressorState[groupNum - 1])">
+                  </a-switch>
+                </div>
+              </div>
+              <div class="control-item">
+                <div class="control-item-l">
+                  <span class="round"></span>
+                  <span>控制模式</span>
+                </div>
+                <div>
+                  <a-switch v-model="airCompressorState[0][`controlModel`]" checked-children="就地" un-checked-children="远程"
+                    @change="handlerControlModel(airCompressorState[0])">
+                  </a-switch>
+                </div>
+              </div>
+              <div class="control-item">
+                <div class="control-item-l">
+                  <span class="round"></span>
+                  <span>是否开启联动</span>
+                </div>
+                <div class="item-data-box" style="display: flex">
+                  <div
+                    :class="{ 'state-icon': true, 'open': monitorData[0].linkState, 'close': !monitorData[0].linkState }">
+                  </div>
+                  <div style="margin-left: 10px;">{{ !monitorData[0].linkState ? '不联动' : '联动' }}</div>
+                </div>
+              </div>
+            </div>
+            <!-- <div class="item" >
+              <assembly-flv ref="video" class="video-box" height="250px"  :url="videoUrl" :destroy="isDestroyVideo" ></assembly-flv>
+            </div> -->
+
+          </div>
+        </div>
+      </div>
+    </div>
+</template>
+<script lang="ts" setup name="nitrogenHome">
+import { onMounted, onUnmounted, ref, watch } from 'vue'
+import { Decoration7 as DvDecoration7 } from '@kjgl77/datav-vue3'
+import fourBorderBg from '../../../comment/components/fourBorderBg.vue'
+import { mountedThree, destroy } from '../nitrogen.threejs'
+import { list } from '../nitrogen.api'
+
+const loading = ref(true)
+
+const kyjs = ['1号空压机', '2号空压机', '3号空压机', '4号空压机'];
+const cqgs = ['1号储气罐', '2号储气罐', '3号储气罐', '4号储气罐'];
+
+const monitorDataGroupNum = ref(3);
+
+const airCompressorState = ref([
+  {
+    id: '',
+    compressRunSigF1: false,
+    controlModel: false
+  },
+  {
+    id: '',
+    compressRunSigF1: false,
+    controlModel: false
+  },
+  {
+    id: '',
+    compressRunSigF1: false,
+    controlModel: false
+  },
+  {
+    id: '',
+    compressRunSigF1: false,
+    controlModel: false
+  }
+]);
+const showMonitorData = [
+  {
+    supVolt1: '电流A(A)',
+    supVolt2: '电流B(A)',
+  },
+  {
+    supVolt3: '电流C(A)',
+    current: '电源电压(V)',
+  },
+  {
+    shock1: '震动X(mm/s)',
+    shock2: '震动Y(mm/s)',
+  },
+  {
+    shock3: '震动Z(mm/s)',
+    noise: '噪声',
+  },
+  {
+    ambTempCol: '环境温度(℃)',
+  },
+];
+const monitorData = ref(new Array(4).fill({
+  strName: '空压机',
+  compressGroupName: '',
+  compressExhaustPressF1: '-',
+  compressSeparatePressF1: '-',
+  compressHostTempF1: '-',
+  compressCrewTempF1: '-',
+  compressRunTimeF1: '-',
+  controlModel: 'LOC'
+}));
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+async function getMonitor() {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = await setTimeout(async () => {
+      await getDataSource();
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+    }, 1000);
+  }
+};
+
+async function getDataSource() {
+  const res = await list({ devicetype: 'pressurefan', pagetype: 'normal' });
+  const dataSource = res.msgTxt[0].datalist || [];
+  dataSource.forEach((data, index) => {
+    const item = data.readData;
+    Object.assign(item, data);
+    item.compressRunSigF1 = item.compressRunSigF1 ? true : false
+    airCompressorState.value[index].id = item.id
+    airCompressorState.value[index].compressRunSigF1 = item.compressRunSigF1
+    airCompressorState.value[index].controlModel = item.controlModel === 'LOC' ? true : false
+    monitorData.value[index] = item
+  });
+  monitorDataGroupNum.value = monitorData.value.length
+  loading.value = false
+};
+
+function handlerDevice(data) {
+  // if (data.length < 1) return
+  // handleAirCompressor({ id: data.id, compressRunF1: data.compressRunSigF1 }).then(res => {
+  //   if (res.success) {
+  //     message.success('操作成功')
+  //   } else {
+  //     message.warning(data.msg)
+  //   }
+  // })
+};
+function resetDevice(data) {
+
+}
+
+function handlerControlModel(data) {
+
+}
+
+watch(monitorDataGroupNum, (newVal) => {
+  if (newVal) {
+    destroy()
+    mountedThree(newVal)
+  }
+})
+onMounted(async () => {
+  await getMonitor()
+})
+
+onUnmounted(() => {
+  destroy();
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+
+</script>
+
+<style lang="less" scoped>
+@ventSpace: zxm;
+
+.nitrogen-box {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
+}
+
+#nitrogenCss3D {
+  .modal-monitor {
+    position: absolute;
+    left: 0px;
+    top: 0px;
+  }
+
+  &:deep(.win) {
+    margin: 0 !important;
+  }
+
+  &:deep(.main) {
+
+    .title {
+      height: 34px;
+      text-align: center;
+      font-weight: 600;
+      color: #7AF5FF;
+      // background-image: url('../../../assets/img/yfj/light.png');
+      background-repeat: no-repeat;
+      background-position-x: center;
+      background-position-y: 100%;
+      background-size: 80%;
+      font-size: 16px;
+    }
+
+    .monitor-item {
+      display: flex;
+      flex-direction: row;
+      width: auto;
+      margin-bottom: 3px;
+
+      .monitor-val {
+        color: #ffb700;
+        display: flex;
+        width: auto;
+
+        .val {
+          width: 80px;
+          font-size: 14px;
+        }
+
+        .unit {
+          color: #ffffffbb;
+          font-size: 14px;
+
+        }
+      }
+    }
+
+    .monitor-title {
+      width: 100px;
+      color: #7AF5FF;
+      font-weight: 400;
+      font-size: 14px;
+    }
+
+    .signal-item {
+      display: flex;
+      justify-content: space-between;
+
+      // margin-bottom: 5px;
+      .signal-round {
+        display: inline-block;
+        width: 8px;
+        height: 8px;
+        border-radius: 50%;
+        margin: 0 10px;
+        position: relative;
+
+        &::after {
+          display: block;
+          content: '';
+          position: absolute;
+          width: 12px;
+          height: 12px;
+          top: -2px;
+          left: -2px;
+          border-radius: 50%;
+        }
+      }
+
+      .signal-round-gry {
+        background-color: #858585;
+
+        &::after {
+          background-color: #85858544;
+          box-shadow: 0 0 1px 1px #85858599;
+        }
+      }
+
+      .signal-round-run {
+        background-color: #67FC00;
+
+        &::after {
+          background-color: #67FC0044;
+          box-shadow: 0 0 1px 1px #c6ff77;
+        }
+      }
+
+      .signal-round-warning {
+        background-color: #E9170B;
+
+        &::after {
+          background-color: #E9170B44;
+          box-shadow: 0 0 1px 1px #E9170B;
+        }
+      }
+    }
+  }
+}
+
+.nitrogen-home {
+  width: 100%;
+  height: calc(100% - 100px);
+  position: fixed;
+  z-index: 99;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  pointer-events: none;
+  top: 100px;
+  .nitrogen-container {
+    width: 100%;
+    height: calc(100%);
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 100px;
+
+    .top-box {
+      width: 100%;
+      padding: 10px;
+      overflow: hidden;
+      display: flex;
+      justify-content: space-between;
+
+      .lr-box {
+        height: fit-content;
+        display: flex;
+        flex-direction: column;
+        position: relative;
+        overflow: hidden;
+        z-index: 9999;
+      }
+
+      .item {
+        width: 285px;
+        height: auto;
+        position: relative;
+        border-radius: 5px;
+        margin-top: 10px;
+        margin-bottom: 0px;
+        pointer-events: auto;
+        color: #fff;
+        overflow: hidden;
+
+        .control-item {
+          height: auto;
+          min-height: 35px;
+          display: flex;
+          flex-direction: row;
+          justify-content: space-between;
+          align-items: center;
+          padding: 5px;
+          margin: 0 10px 0 3px;
+          pointer-events: auto;
+          background: linear-gradient(to right, #0063CD22, #0063CD04);
+
+          margin-bottom: 5px;
+          border-width: 1px;
+          border-style: dashed;
+
+          border-image: linear-gradient(to right, #008ccd66, #0063CD04)1 1;
+          border-radius: 5px;
+
+          &:last-child {
+            margin-bottom: 0
+          }
+
+          .control-item-l {
+            display: flex;
+            align-items: center;
+            font-size: 14px;
+
+            .round {
+              display: inline-block;
+              width: 3px;
+              height: 3px;
+              padding: 1px;
+              border-radius: 50%;
+              background-color: #3DF6FF;
+              margin-right: 5px;
+              box-shadow: 0 0 1px 1px #64f7ff;
+            }
+          }
+
+          .control-item-r {
+            text-align: right;
+          }
+
+          .button-box {
+            position: relative;
+            padding: 5px;
+            border: 1px transparent solid;
+            background-clip: border-box;
+            border-radius: 5px;
+            margin-left: 8px;
+          }
+
+          .a-button {
+            pointer-events: auto;
+          }
+
+          &::v-deep .a-button--mini {
+            padding: 6px 10px;
+          }
+
+          &::v-deep .a-button--mini.is-round {
+            padding: 6px 10px;
+          }
+        }
+
+        .base-title {
+          width: calc(100% - 60px);
+          text-align: center;
+          color: #00d8ff;
+        }
+
+        .state-item {
+          display: flex;
+          flex-direction: row;
+          padding: 5px;
+
+          .item-col {
+            width: 50%;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            padding-right: 4px;
+
+            .state-title {
+              color: #ffffffcc;
+              flex: 9;
+              font-size: 14px;
+
+              .unit {
+                // color: #ffffffbb;
+              }
+            }
+
+            .state-val {
+              flex: 1;
+              color: #e4a300;
+              margin-right: 5px;
+              text-align: right;
+              font-size: 14px;
+            }
+          }
+        }
+
+        .signal-box {
+          margin: 5px 0;
+          display: flex;
+          align-items: center;
+
+          .signal-title {
+            color: #7AF5FF;
+            margin: 0 5px;
+          }
+
+          &:last-child {
+            margin-right: 0px;
+          }
+        }
+
+        .list-item {
+          padding: 0 10px;
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+
+          .item-data-key {
+            color: #ffffff99;
+          }
+        }
+
+        .item-data-box {
+          color: #fff;
+
+          .state-icon {
+            display: inline-block;
+            width: 12px;
+            height: 12px;
+            border-radius: 12px;
+          }
+
+          .open {
+            border: 5px solid #133a56;
+            background: #4ecb73;
+          }
+
+          .close {
+            border: 5px solid #192961;
+            background: #6d7898;
+          }
+        }
+      }
+
+      .item-l {
+        width: 335px;
+
+        .monitor-box {
+          width: 335px;
+          background-color: #ffffff05;
+          margin-left: 2px;
+          border-radius: 5px;
+          backdrop-filter: blur(10px);
+        }
+      }
+
+      .right-box {
+        .item {
+          height: auto;
+        }
+      }
+
+      .left-box {
+        width: 365px;
+
+        .control-item {
+          height: 36px;
+        }
+      }
+    }
+  }
+}</style>

+ 57 - 406
src/views/vent/monitorManager/nitrogen/index.vue

@@ -1,160 +1,71 @@
 <template>
-  <div class="threejs-Object-CSS"></div>
-  <div id="nitrogen3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"></div>
-  <div class="vent-home">
-    <div class="vent-home-header">
+  <div class="nitrogen-box">
+    <div class="nitrogen-home-header">
       <Decoration5 class="header-icon" :dur="2" :color="['#21437F', '#2CF7FE']" style="width:500px;height:40px;" />
       <div class="header-text">智能压风管控系统</div>
     </div>
-    
-    <div class="nitrogen-container">
-      <div class="top-box">
-          <!-- 左边监测数据 -->
-          <div class="lr-box left-box">
-            <div class="item item-l" v-for="groupNum in monitorDataGroupNum" :key="groupNum">
-              <dv-decoration7 style="height:30px;">
-                <div class="base-title">空压机{{ groupNum }}</div>
-              </dv-decoration7>
-              <div class="monitor-box">
-                <div class="state-item" v-for="(data, index) in showMonitorData" :key="index">
-                  <div class="item-col" v-if="Object.values(data).length > 0">
-                    <span class="state-title">{{ Object.values(data)[0] }} :</span>
-                    <span class="state-val">{{ (monitorData.length > 0 && monitorData[groupNum - 1][Object.keys(data)[0]]) >= 0 ? monitorData[groupNum - 1][Object.keys(data)[0]] : '-' }}</span>
-                  </div>
-                  <div class="item-col" v-if="Object.values(data).length > 1">
-                    <span class="state-title">{{ Object.values(data)[1] }} :</span>
-                    <span class="state-val">{{ (monitorData.length > 0 && monitorData[groupNum - 1][Object.keys(data)[1]]) >= 0 ? monitorData[groupNum - 1][Object.keys(data)[1]] : '-' }}</span>
-                  </div>
-                </div>
-              </div>
-            </div>
-          </div>
-          <!-- 右边控制状态 -->
-          <div class="lr-box right-box">
-            <div class="item" >
-              <div class="control-item">
-                <div class="control-item-l">
-                    <!-- <img src="@/assets/img/yccz.png" alt="" width="36px" height="36px" style="margin-right: 10px;"> -->
-                    <span style="font-size: 18px;">远程控制</span>
-                </div>
-              </div>
-              <div class="control-item" v-for="groupNum in monitorDataGroupNum" :key="groupNum">
-                <div class="control-item-l">
-                  <span class="round"></span>
-                  <span>{{ kyjs[groupNum - 1] }}</span>
-                </div>
-                <div class="control-item-r" style="display: flex; align-items: center;">
-                  <a-switch
-                    v-model="airCompressorState[groupNum - 1][`compressRunSigF1`]"
-                    checked-children="开启"
-                    un-checked-children="关闭"
-                    :disabled="airCompressorState[groupNum - 1][`controlModel`]"
-                    @change="handlerDevice(airCompressorState[groupNum - 1])">
-                  </a-switch>
-                  <div class="button-box">
-                    <!-- <a-button type="primary" siz="small" @click="resetDevice(airCompressorState[groupNum - 1])">复位</a-button> -->
-                    <span class="">复位</span>
-                  </div>
-                </div>
-              </div>
-              <div class="control-item">
-                <div class="control-item-l">
-                  <span class="round"></span>
-                  <span>控制模式</span>
-                </div>
-                <div>
-                  <a-switch
-                    v-model="airCompressorState[0][`controlModel`]"
-                    checked-children="就地"
-                    un-checked-children="远程"
-                    @change="handlerControlModel(airCompressorState[0])">
-                  </a-switch>
-                </div>
-              </div>
-            </div>
-            <!-- <div class="item" >
-              <assembly-flv ref="video" class="video-box" height="250px"  :url="videoUrl" :destroy="isDestroyVideo" ></assembly-flv>
-            </div> -->
-
-          </div>
-        </div>
-    </div>
-    <div class="bottom-btn-group">  
-      <div v-for="item in bottomBtnList" :key="item.value" class="vent-row-center btn-item" @click="setBtn('click', item)" @mouseenter="setBtn('over', item)" @mouseleave="setBtn('leave', item)">
-        <dv-decoration11 :color="isBtnActive === item.value ? activeColors : item.isHover ? activeColors : noActiveColors" style="width:200px;height:60px;">
-          {{ item.text }}
+    <nitrogenHome v-if="isBtnActive == 'nitrogen_page'" />
+    <nitrogenEcharts v-if="isBtnActive == 'yfj_monitor_echarts'"/>
+    <nitrogenHistory v-if="isBtnActive == 'yfj_history'"/>
+    <nitrogenHandleHistory v-if="isBtnActive == 'yfj_handler_history'"/>
+    <nitrogenAlarmHistory v-if="isBtnActive == 'yfj_faultRecord'"/>
+    <div class="bottom-btn-group">
+      <div v-for="item in navList" :key="item.pathName" class="vent-row-center btn-item" @click="setBtn('click', item)"
+        @mouseenter="setBtn('over', item)" @mouseleave="setBtn('leave', item)">
+        <dv-decoration11
+          :color="isBtnActive === item.pathName ? activeColors : item.isHover ? activeColors : noActiveColors"
+          style="width:200px;height:60px;">
+          {{ item.title }}
         </dv-decoration11>
       </div>
     </div>
   </div>
+  
 </template>
 <script lang="ts" setup>
-import { onMounted, onUnmounted, ref } from 'vue'
-import { Decoration5, Decoration11 as DvDecoration11, Decoration7 as DvDecoration7, BorderBox7 as DvBorderBox7 } from '@kjgl77/datav-vue3'
-import { bottomBtnList } from './nitrogen.data'
-import { mountedThree } from './nitrogen.threejs'
-
+import { ref } from 'vue'
+import nitrogenHome from './components/nitrogenHome.vue'
+import nitrogenEcharts from './components/nitrogenEcharts.vue'
+import nitrogenHistory from './components/nitrogenHistory.vue'
+import nitrogenHandleHistory from './components/nitrogenHandleHistory.vue'
+import nitrogenAlarmHistory from './components/nitrogenAlarmHistory.vue'
+import {  Decoration11 as DvDecoration11, Decoration5 } from '@kjgl77/datav-vue3'
+
+const isBtnActive = ref('nitrogen_page')
 const activeColors = ['#009BFF', '#28DBE4']
 const noActiveColors = ['#aaa', '#aaa']
-const isBtnActive = ref('workFace')
-
-const kyjs = ['1号空压机', '2号空压机', '3号空压机', '4号空压机'];
-// const cqgs = ['1号储气罐', '2号储气罐', '3号储气罐', '4号储气罐'];
-// const checkedKyjs = new Set(['1号空压机']);
-const monitorDataGroupNum = 3;
-const airCompressorState = ref([
+const navList = ref([
   {
-    id: '',
-    compressRunSigF1: false,
-    controlModel: false
+    title: '监控界面',
+    pathName: 'nitrogen_page',
+    isHover: true
   },
+  // {
+  //   title: '关键节点监测',
+  //   pathName: 'critical_node',
+  //   isHover: false
+  // },
   {
-    id: '',
-    compressRunSigF1: false,
-    controlModel: false
+    title: '实时曲线',
+    pathName: 'yfj_monitor_echarts',
+    isHover: false
   },
   {
-    id: '',
-    compressRunSigF1: false,
-    controlModel: false
-  },
-  {
-    id: '',
-    compressRunSigF1: false,
-    controlModel: false
-  }
-]);
-const showMonitorData = [
-  {
-    supVolt1: '电流A(A)',
-    supVolt2: '电流B(A)',
+    title: '压风机历史记录',
+    pathName: 'yfj_history',
+    isHover: false
   },
   {
-    supVolt3: '电流C(A)',
-    current: '电源电压(V)',
+    title: '操作历史记录',
+    pathName: 'yfj_handler_history',
+    isHover: false
   },
   {
-    shock1: '震动X(mm/s)',
-    shock2: '震动Y(mm/s)',
-  },
-  {
-    shock3: '震动Z(mm/s)',
-    noise: '噪声',
-  },
-  {
-    ambTempCol: '环境温度(℃)',
-  },
-];
-const monitorData = ref(new Array(4).fill({
-  strName: '空压机',
-  compressGroupName: '',
-  compressExhaustPressF1: '-',
-  compressSeparatePressF1: '-',
-  compressHostTempF1: '-',
-  compressCrewTempF1: '-',
-  compressRunTimeF1: '-',
-  controlModel: 'LOC'
-}));
+    title: '故障诊断历史记录',
+    pathName: 'yfj_faultRecord',
+    isHover: false
+  }
+])
 
 
 function setBtn(type, activeObj) {
@@ -163,75 +74,16 @@ function setBtn(type, activeObj) {
   } else if (type === 'leave') {
     activeObj.isHover = false
   } else if (type === 'click') {
-    isBtnActive.value = activeObj.value
+    isBtnActive.value = activeObj.pathName
   }
-}
-
-function handlerDevice(data) {
-  // if (data.length < 1) return
-  // handleAirCompressor({ id: data.id, compressRunF1: data.compressRunSigF1 }).then(res => {
-  //   if (res.success) {
-  //     message.success('操作成功')
-  //   } else {
-  //     message.warning(data.msg)
-  //   }
-  // })
-};
-function resetDevice(data) {
-
-}
-
-function handlerControlModel(data) {
 
 }
 
-
-onMounted(() => {
-  mountedThree()
-})
-
-onUnmounted(() => {
-
-})
-
 </script>
-<style lang="less">
-@import '/@/design/vent/modal.less';
 
-.@{ventSpace}-select-dropdown {
-  border-bottom: 1px solid #ececec66;
-  background: transparent !important;
-  backdrop-filter: blur(50px);
-
-  .@{ventSpace}-select-item {
-    color: #fff !important;
-  }
-
-  .@{ventSpace}-select-item-option-selected,
-  .@{ventSpace}-select-item-option-active {
-    background-color: #00678b66 !important;
-  }
-
-  .@{ventSpace}-select-item:hover {
-    background-color: #008fc366 !important;
-  }
-}
-</style>
 <style lang="less" scoped>
 @ventSpace: zxm;
-
-.vent-home {
-  width: 100%;
-  height: calc(100%);
-  position: fixed;
-  z-index: 99;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  align-items: center;
-  pointer-events: none;
-
-  .vent-home-header {
+.nitrogen-home-header {
     width: 100%;
     height: 100px;
     position: fixed;
@@ -252,203 +104,20 @@ onUnmounted(() => {
       font-size: 24px;
     }
   }
-
-  .nitrogen-container {
-    width: 100%;
-    height: calc(100% - 200px);
-    display: flex;
-    justify-content: space-between;
-    margin-bottom: 100px;
-    .top-box{
-      width: 100%;
-      padding: 10px;
-      overflow: hidden;
-      display: flex;
-      justify-content: space-between;
-      .lr-box{
-        height: fit-content;
-        display: flex;
-        flex-direction: column;
-        position: relative;
-        overflow: hidden;
-        z-index: 9999;
-      }
-      .item{
-        width: 285px;
-        height: auto;
-        position: relative;
-        border-radius: 5px;
-        margin-top: 10px;
-        margin-bottom: 0px;
-        pointer-events: auto;
-        color: #fff;
-        overflow: hidden;
-      
-        .control-item{
-          height: auto;
-          min-height: 35px;
-          display: flex;
-          flex-direction: row;
-          justify-content: space-between;
-          align-items: center;
-          padding: 5px;
-          margin: 0 10px 0 3px;
-          pointer-events: auto;
-          background: linear-gradient(to right, #0063CD22, #0063CD04);
-
-          margin-bottom: 5px;
-          border-width: 1px;
-          border-style: dashed;
-
-          border-image: linear-gradient(to right, #008ccd66, #0063CD04)1 1;
-          border-radius: 5px;
-          &:last-child{
-            margin-bottom: 0
-          }
-          .control-item-l{
-            display: flex;
-            align-items: center;
-            font-size: 14px;
-            .round{
-              display: inline-block;
-              width: 3px;
-              height: 3px;
-              padding: 1px;
-              border-radius: 50%;
-              background-color: #3DF6FF;
-              margin-right: 5px;
-              box-shadow: 0 0 1px 1px #64f7ff;
-            }
-          }
-          .control-item-r{
-            text-align: right;
-          }
-          .button-box{
-            position: relative;
-            padding: 5px;
-            border:1px transparent solid;
-            background-clip: border-box;
-            border-radius: 5px;
-            margin-left: 8px;
-          }
-          .a-button{
-            pointer-events: auto;
-          }
-          &::v-deep .a-button--mini {
-            padding: 6px 10px;
-          }
-          &::v-deep .a-button--mini.is-round{
-            padding: 6px 10px;
-          }
-        }
-        .base-title {
-          width: calc(100% - 60px);
-          text-align: center;
-          color: #00d8ff;
-        }
-        .state-item{
-          display: flex;
-          flex-direction: row;
-          padding: 5px;
-          .item-col{
-            width: 50%;
-            display: flex;
-            justify-content: center;
-            align-items: center;
-            padding-right: 4px;
-            .state-title{
-              color: #ffffffcc;
-              flex: 9;
-              font-size: 14px;
-              .unit{
-                // color: #ffffffbb;
-              }
-            }
-            .state-val{
-              flex: 1;
-              color: #e4a300;
-              margin-right: 5px;
-              text-align: right;
-              font-size: 14px;
-            }
-          }
-        }
-        .signal-box{
-          margin: 5px 0;
-          display: flex;
-          align-items: center;
-          .signal-title{
-            color: #7AF5FF;
-            margin: 0 5px;
-          }
-
-          &:last-child{
-              margin-right: 0px;
-            }
-        }
-
-        .list-item {
-          padding: 0 10px;
-          display: flex;
-          justify-content: space-between;
-          align-items: center;
-          .item-data-key{
-            color: #ffffff99;
-          }
-        }
-        .item-data-box {
-            color: #fff;
-            .state-icon {
-              display: inline-block;
-              width: 12px;
-              height: 12px;
-              border-radius: 12px;
-            }
-
-            .open {
-              border: 5px solid #133a56;
-              background: #4ecb73;
-            }
-
-            .close {
-              border: 5px solid #192961;
-              background: #6d7898;
-            }
-          }
-      }
-      .item-l{
-        width: 335px;
-        .monitor-box{
-          width: 335px;
-          background-color: #ffffff05;
-          margin-left: 2px;
-          border-radius: 5px;
-          backdrop-filter: blur(10px);
-        }
-      }
-      .right-box{
-        .item{
-          height: auto;
-        }
-      }
-      .left-box{
-        width: 365px;
-        .control-item{
-          height: 36px;
-        }
-      }
-    }
-  }
-
+.nitrogen-box{
+  width: 100%;
+  height: 100%;
+  display: flex;
+  justify-content: center;
   .bottom-btn-group {
     display: flex;
     position: fixed;
     width: calc(100% - 400px);
     height: 100px;
-    bottom: 20px;
+    bottom: 10px;
     align-items: center;
     justify-content: center;
-
+    z-index: 2;
     .btn-item {
       width: 200px;
       height: 60px;
@@ -458,24 +127,6 @@ onUnmounted(() => {
       pointer-events: auto;
     }
   }
-
 }
 
-:deep(.zxm-select) {
-  width: 300px;
-
-  .@{ventSpace}-select-selector {
-    background: transparent !important;
-    border: none !important;
-    box-shadow: none !important;
-
-    .zxm-select-selection-item {
-      color: #fff !important;
-      font-size: 20px;
-    }
-  }
-
-  .@{ventSpace}-select-arrow {
-    color: #fff !important;
-  }
-}</style>
+</style>

+ 17 - 0
src/views/vent/monitorManager/nitrogen/nitrogen.api.ts

@@ -0,0 +1,17 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  list = '/monitor/device',
+  baseList = '/safety/ventanalyDeviceInfo/list',
+}
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });
+
+/**
+ * 保存或者更新用户
+ * @param params
+ */
+export const getTableList = (params) => defHttp.get({ url: Api.baseList, params });

+ 15 - 10
src/views/vent/monitorManager/nitrogen/nitrogen.data.ts

@@ -1,28 +1,33 @@
 import { ref } from 'vue';
 export const bottomBtnList = ref([
   {
-    text: '工作面智能管控',
-    value: 'workFace',
+    text: '监控界面',
+    value: 'nitrogenMonitor',
     isHover: false,
   },
   {
-    text: '实时网络解算',
-    value: 'netWork',
+    text: '关键节点监测',
+    value: 'nitrogenNode',
     isHover: false,
   },
   {
-    text: '关键通风路线',
-    value: 'mainPath',
+    text: '实时曲线',
+    value: 'nitrogenEcharts',
     isHover: false,
   },
   {
-    text: '通风设备监测',
-    value: 'deviceMonitor',
+    text: '压风机历史记录',
+    value: 'nitrogenHistory',
     isHover: false,
   },
   {
-    text: '通风预警监测',
-    value: 'warningMonitor',
+    text: '操作历史记录',
+    value: 'nitrogenHandleHistory',
+    isHover: false,
+  },
+  {
+    text: '故障诊断历史记录',
+    value: 'nitrogenWarningHistory',
     isHover: false,
   },
 ]);

+ 67 - 231
src/views/vent/monitorManager/nitrogen/nitrogen.dishang.threejs.ts

@@ -1,6 +1,6 @@
 import * as THREE from 'three';
-import { getTextCanvas, addEnvMap } from '/@/utils/threejs/util';
-
+import { getTextCanvas, addEnvMap, setModalCenter } from '/@/utils/threejs/util';
+import { CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
 import * as dat from 'dat.gui';
 const gui = new dat.GUI();
 gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
@@ -16,6 +16,7 @@ class Nitrogen {
   playerStartClickTime1 = new Date().getTime();
   playerStartClickTime2 = new Date().getTime();
   deviceRunState = '';
+  nitrogenNum = 0;
 
   constructor(model) {
     this.model = model;
@@ -65,149 +66,22 @@ class Nitrogen {
 
   // 设置模型位置
   setModalPosition() {
-    this.group?.scale.set(22, 22, 22);
-    this.group?.position.set(-25, 25, 15);
-  }
-
-  addText(selectData) {
-    if (!this.group) {
-      return;
+    if (this.nitrogenNum == 4) {
+      this.group.position.set(0, -17, 3);
+      this.group?.scale.set(24.0, 24.0, 24.0);
+    }
+    if (this.nitrogenNum == 3) {
+      this.group.position.set(0, -12, 3);
+      this.group?.scale.set(24.0, 24.0, 24.0);
+    }
+    if (this.nitrogenNum == 2) {
+      this.group.position.set(0, 0.42, 1.21);
+      this.group?.scale.set(24.0, 24.0, 24.0);
+    }
+    if (this.nitrogenNum == 1) {
+      this.group.position.set(0, 8, 3.0);
+      this.group?.scale.set(24.0, 24.0, 24.0);
     }
-    const textArr = [
-      {
-        text: `龙门式测风装置`,
-        font: 'normal 32px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 170,
-        y: 40,
-      },
-      {
-        text: `风量(m3/min):`,
-        font: 'normal 29px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 2,
-        y: 115,
-      },
-      {
-        text: `${selectData.m3 ? selectData.m3 : '-'}`,
-        font: 'normal 29px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 200,
-        y: 115,
-      },
-      {
-        text: `气源压力(MPa): `,
-        font: 'normal 29px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 2,
-        y: 182,
-      },
-      {
-        text: `${selectData.temperature ? selectData.temperature : '-'}`,
-        font: 'normal 29px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 215,
-        y: 182,
-      },
-      {
-        text: `Va(m/s):`,
-        font: 'normal 29px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 2,
-        y: 245,
-      },
-      {
-        text: `${selectData.va ? selectData.va : '-'}`,
-        font: 'normal 29px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 130,
-        y: 246,
-      },
-      {
-        text: `V1(m/s):`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 331,
-        y: 115,
-      },
-      {
-        text: `${selectData.incipientWindSpeed1 ? selectData.incipientWindSpeed1 : '-'}`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 455,
-        y: 115,
-      },
-      {
-        text: `V2(m/s):`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 330,
-        y: 182,
-      },
-      {
-        text: `${selectData.incipientWindSpeed2 ? selectData.incipientWindSpeed2 : '-'}`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 452,
-        y: 182,
-      },
-      {
-        text: `V3(m/s):`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 330,
-        y: 245,
-      },
-      {
-        text: `${selectData.incipientWindSpeed3 ? selectData.incipientWindSpeed3 : '-'}`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 452,
-        y: 245,
-      },
-      {
-        text: `煤炭科学技术研究院有限公司研制`,
-        font: 'normal 28px Arial',
-        color: '#009900',
-        strokeStyle: '#002200',
-        x: 60,
-        y: 302,
-      },
-    ];
-
-    getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-      const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-      const textMaterial = new THREE.MeshBasicMaterial({
-        map: textMap, // 设置纹理贴图
-        transparent: true,
-        side: THREE.DoubleSide, // 这里是双面渲染的意思
-      });
-      textMaterial.blending = THREE.CustomBlending;
-      const monitorPlane = this.group?.getObjectByName('monitorText');
-      if (monitorPlane) {
-        monitorPlane.material = textMaterial;
-      } else {
-        const planeGeometry = new THREE.PlaneGeometry(560, 346); // 平面3维几何体PlaneGeometry
-        const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-        planeMesh.name = 'monitorText';
-        planeMesh.scale.set(0.0022, 0.0022, 0.0022);
-        planeMesh.position.set(3.25, -0.002, -0.41);
-        this.group?.add(planeMesh);
-      }
-    });
   }
 
   /* 提取风门序列帧,初始化前后门动画 */
@@ -254,6 +128,40 @@ class Nitrogen {
     model.material = transparentMaterial;
   };
 
+  addCssText = () => {
+    if (this.nitrogenNum > 0) {
+      for (let i = 0; i < this.nitrogenNum; i++) {
+        const nitrogenModal = this.group.getObjectByName('nitrogenModal' + i) as THREE.Object3D;
+        if (!nitrogenModal.getObjectByName('monitorNitrogenText')) {
+          const element = document.getElementById('nitrogenMonitor' + (i + 1)) as HTMLElement;
+          element.style.top = '0px';
+          element.style.left = '0px';
+          const nitrogenMonitorCSS3D = new CSS3DSprite(element);
+          nitrogenMonitorCSS3D.name = 'monitorNitrogenText';
+          nitrogenMonitorCSS3D.scale.set(0.003, 0.003, 0.003);
+          if (i == 0) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0);
+          if (i == 1) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0.04);
+          if (i == 2) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0.08);
+          if (i == 3) nitrogenMonitorCSS3D.position.set(-0.89, 0.31, 0.12);
+          nitrogenModal.add(nitrogenMonitorCSS3D);
+        }
+        if (!nitrogenModal.getObjectByName('cqgMonitorText')) {
+          const element = document.getElementById('cqgMonitor' + (i + 1)) as HTMLElement;
+          element.style.top = '0px';
+          element.style.left = '0px';
+          const cqgMonitorCSS3D = new CSS3DSprite(element);
+          cqgMonitorCSS3D.name = 'cqgMonitorText';
+          cqgMonitorCSS3D.scale.set(0.003, 0.003, 0.003);
+          if (i == 0) cqgMonitorCSS3D.position.set(1.24, 0.49, 0.0);
+          if (i == 1) cqgMonitorCSS3D.position.set(1.24, 0.49, 0.04);
+          if (i == 2) cqgMonitorCSS3D.position.set(1.24, 0.49, 0.08);
+          if (i == 3) cqgMonitorCSS3D.position.set(1.24, 0.49, 0.12);
+          nitrogenModal.add(cqgMonitorCSS3D);
+        }
+      }
+    }
+  };
+
   /**
    * 处理杯子的纹理和杯子外层透明壳子
    */
@@ -292,99 +200,27 @@ class Nitrogen {
     withVolume.push(transparentWrap);
   };
 
-  mountedThree() {
+  mountedThree(nitrogenNum) {
+    this.nitrogenNum = nitrogenNum;
     return new Promise((resolve) => {
+      if (nitrogenNum < 1) {
+        resolve(null);
+        return;
+      }
       this.model.setModel([this.modelName]).then(async (gltf) => {
         const nitrogenGroup = new THREE.Object3D();
-        const nitrogenModal = gltf[0].clone();
-        nitrogenModal.name = 'nitrogenModal0';
-        nitrogenModal;
-
-        const nitrogenModal1 = gltf[0].clone();
-        nitrogenModal1.name = 'nitrogenModal1';
-        nitrogenModal1.position.set(0, 0, 1.29);
-
-        const texture = await addEnvMap('royal_esplanade_1k', this.model);
-
-        const material = new THREE.MeshPhysicalMaterial({
-          side: THREE.DoubleSide,
-          // specularColor: new Color("#ffffff"),
-          // color: new Color(0xffa000),
-          color: 0xffffff,
-          //类似透明度
-          // transmission: 0.5,
-          opacity: 0,
-          metalness: 0,
-          roughness: 0.12,
-          ior: 1.8,
-          thickness: 0.39, //透过看物体的模糊程度
-          specularIntensity: 1.1,
-          // color: new THREE.Color(0x72531e),
-          transmission: 1,
-          // envMap: texture,
-        });
-
-        nitrogenModal.children[0].children[1].material = new THREE.MeshPhysicalMaterial({
-          side: THREE.DoubleSide,
-          transparent: true,
-          opacity: 0.1,
-          color: 0xffffff,
-          //类似透明度
-          // transmission: 0.5,
-          metalness: 0,
-          roughness: 0.2,
-          ior: 1.3,
-          thickness: 1.2, //透过看物体的模糊程度
-          specularIntensity: 1,
-          // color: new THREE.Color(0x72531e),
-          transmission: 0,
-        });
-
-        gui.add(material, 'metalness', 0, 1).onChange(function (value) {
-          material.metalness = Number(value);
-        });
-        gui.add(material, 'roughness', 0, 1).onChange(function (value) {
-          material.roughness = Number(value);
-        });
-        gui.add(material, 'thickness', 0, 2).onChange(function (value) {
-          material.thickness = Number(value);
-        });
-        gui.add(material, 'specularIntensity', 0, 2).onChange(function (value) {
-          material.specularIntensity = Number(value);
-        });
-        gui.add(material, 'transmission', 0, 1).onChange(function (value) {
-          material.transmission = Number(value);
-        });
-        gui.add(material, 'ior', 0, 3).onChange(function (value) {
-          material.ior = Number(value);
-        });
-
-        nitrogenModal.children[0].children[0].material = material;
-
-        nitrogenGroup.add(nitrogenModal);
-        nitrogenGroup.add(nitrogenModal1);
+        for (let i = 0; i < nitrogenNum; i++) {
+          const nitrogenModal = gltf[0].clone();
+          nitrogenModal.name = 'nitrogenModal' + i;
+          nitrogenModal.position.set(0, 0, -1.29 * i);
+          nitrogenGroup.add(nitrogenModal);
+        }
 
         this.group = nitrogenGroup;
-        this.group.name = this.modelName;
-
-        // this.handleGlassAndWrap(
-        //   this.group,
-        //   withVolume,
-        //   glass1,
-        //   roughnessParams,
-        //   10,
-        //   new THREE.Vector3(60, -2.4, -120),
-        //   new THREE.Vector3(1.5, 1, -3)
-        // );
-        // this.handleGlassAndWrap(
-        //   objects,
-        //   withVolume,
-        //   glass3,
-        //   { ...roughnessParams, color: new THREE.Color(0x72531e), transmission: 0.7 },
-        //   5,
-        //   new THREE.Vector3(-42, -2.5, -97)
-        // );
 
+        this.group.name = this.modelName;
+        setModalCenter(this.group);
+        this.addCssText();
         this.setModalPosition();
         this.addLight();
         resolve(null);

+ 11 - 7
src/views/vent/monitorManager/nitrogen/nitrogen.threejs.ts

@@ -27,7 +27,8 @@ const mouseEvent = (event) => {
     -((-model.canvasContainer.getBoundingClientRect().top + event.clientY) / (model.canvasContainer.clientHeight * heightScale)) * 2 + 1;
   (model.rayCaster as THREE.Raycaster).setFromCamera(model.mouse, model.camera as THREE.Camera);
 
-  updateAxisCenter(model, event);
+  // console.log('相机与控制器信息--->', model.camera, model.orbitControls);
+  // updateAxisCenter(model, event);
 
   if (group) {
     const intersects = model.rayCaster?.intersectObjects(group.children, false) as THREE.Intersection[];
@@ -63,7 +64,7 @@ export const setModelType = (type) => {
     // 显示双道风窗
     if (modalType === 'nitrogen') {
       group = nitrogenObj.group;
-      setModalCenter(group);
+      // setModalCenter(group);
       const oldCameraPosition = { x: -1000, y: 100, z: 500 };
       const oldControlsPosition = { x: -10, y: 10, z: 10 };
       model.scene.add(nitrogenObj.group);
@@ -72,8 +73,11 @@ export const setModelType = (type) => {
         await animateCamera(
           oldCameraPosition,
           oldControlsPosition,
-          { x: -0.24658823766780538, y: 35.50352092191473, z: 83.90511756512278 },
-          { x: 1.5582599568763913, y: -3.2828007511721147, z: 2.2606374587827234 },
+          // { x: -0.24658823766780538, y: 35.50352092191473, z: 83.90511756512278 },
+          // { x: -0.24658823766780538, y: 35.50352092191473, z: 83.90511756512278 },
+          // { x: 1.5582599568763913, y: -3.2828007511721147, z: 2.2606374587827234 },
+          { x: -0.03221356849453339, y: 60.58380705766696, z: 66.35361856273981 },
+          { x: -0.04856971136953342, y: 0.6442166711669518, z: 0.7632993277398138 },
           model,
           0.8
         );
@@ -82,14 +86,14 @@ export const setModelType = (type) => {
   });
 };
 
-export const mountedThree = () => {
+export const mountedThree = (nitrogenNum) => {
   return new Promise(async (resolve) => {
-    model = new UseThree('#nitrogen3D');
+    model = new UseThree('#nitrogen3D', '#nitrogenCss3D');
     model.setEnvMap('test1');
     model.renderer.toneMappingExposure = 1;
     model.canvasContainer?.addEventListener('mousedown', mouseEvent.bind(null));
     nitrogenObj = new Nitrogen(model);
-    await nitrogenObj.mountedThree();
+    await nitrogenObj.mountedThree(nitrogenNum);
     setModelType('nitrogen');
     resolve(null);
     model.animate();

+ 1 - 1
src/views/vent/monitorManager/sensorMonitor/index.vue

@@ -77,7 +77,7 @@
       </a-tab-pane>
       <a-tab-pane key="4" tab="操作历史">
         <div class="tab-item box-bg">
-          <HandlerHistoryTable columns-type="alarm_history" device-type="modelsensor" :device-list-api="baseList" designScope="alarm-history" />
+          <HandlerHistoryTable columns-type="operatorhistory" device-type="modelsensor" :device-list-api="baseList" designScope="alarm-history" />
         </div>
       </a-tab-pane>
     </a-tabs>

+ 1 - 1
src/views/vent/monitorManager/windowMonitor/index.vue

@@ -102,7 +102,7 @@
         </a-tab-pane>
         <a-tab-pane key="5" tab="操作历史">
           <div class="tab-item">
-            <HandlerHistoryTable columns-type="alarm_history" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
+            <HandlerHistoryTable columns-type="operatorhistory" device-type="fanlocal" :device-list-api="baseList" designScope="alarm-history" />
           </div>
         </a-tab-pane>
       </a-tabs>

+ 0 - 1
src/views/vent/monitorManager/windowMonitor/window.api.ts

@@ -1,5 +1,4 @@
 import { defHttp } from '/@/utils/http/axios';
-import { Modal } from 'ant-design-vue';
 
 enum Api {
   list = '/monitor/device',